【问题标题】:Clojure - reset! atom causing a stack overflowClojure - 重置! atom导致堆栈溢出
【发布时间】:2011-04-22 00:07:16
【问题描述】:

我正在学习 clojure,只是在玩 atom 和 refs。这是一个简单的树实现,但是在执行 add-child 方法时会导致堆栈溢出:

(ns mytree)

(defprotocol PNode
  (add-child [this parent] "add 'this' node to the parent"))

(defrecord Node [id parent name children]
  PNode
  (add-child [this p]
     (println "adding this to children of parent")       
     (dosync
      (alter (:children p) conj this))

     ;following causes a stack overflow -why?
;        (println "reseting parent of this")
;        (reset! parent p)

     ))

(defn create-node [id name]
  (Node. id (atom nil) name (ref ())))

这是来自 REPL 的示例会话:

>mytree> (def root (create-node 1 "CEO"))
>#'mytree/root
>mytree> (def child (create-node 2 "VP1"))
>#'mytree/child
>mytree> (add-child child root)

>adding this to children of parent

>(#:mytree.Node{:id 2, :parent #<Atom@4dffa9d: nil>, :name "VP1", :children #<Ref@cbe5beb:      ()>})

>mytree> root
>#:mytree.Node{:id 1, :parent #<Atom@44896098: nil>, :name "CEO", :children #<Ref@2a75733a: >(#:mytree.Node{:id 2, :parent #<Atom@4dffa9d: nil>, :name "VP1", :children #<Ref@cbe5beb: ()>})>}
>mytree> (def child2 (create-node 3 "VP2"))
>#'mytree/child2

resetting parent to child2 works
>mytree> (reset! (:parent child) child2)
>#:mytree.Node{:id 3, :parent #<Atom@43c32b82: nil>, :name "VP2", :children #<Ref@425d868f: ()>}

but resetting parent to root causes stack overflow - why??
>mytree> (reset! (:parent child) root)
>; Evaluation aborted.

正如您在上面看到的,将 child 的 parent 重置为 child2 是可行的,但将其重置为 root 会导致堆栈溢出。你能帮我理解为什么吗?

【问题讨论】:

    标签: clojure stack overflow reset


    【解决方案1】:

    实际上不是 reset!,而是 REPL 试图打印(无限)嵌套值。

    试试这个:

    (set! *print-level* 10)
    

    这将限制分层对象的递归打印。

    【讨论】:

    • 感谢您的回答-您能解释一下这样做时递归的来源吗?我只是想将子节点的父“指针”设置为父节点。不明白为什么会导致无限递归。
    • 因为如果root 的父级是child,而child 的父级是root,那么您就有一个cyclereset! 的返回值返回 REPL 尝试打印的新值,如果没有 *print-level* 值,它将永远持续下去。
    • 好的 - 我想我明白发生了什么。 REPL 正在尝试遍历所有链接以打印结构,并且由于之前将 child 添加到 root,现在当 child 的 parent 设置为 root 并且当 REPL 尝试打印 root 时,它将打印孩子并跟随他们的链接导致返回根,因此在尝试打印时无限递归。
    • 谢谢约翰 - 是的,我刚刚意识到并发布了但看起来你更早发布了答案。
    猜你喜欢
    • 2015-12-21
    • 2023-03-14
    • 2015-05-21
    • 2014-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多