Clojure - сброс! атом вызывает переполнение стека - PullRequest
4 голосов
/ 22 апреля 2011

Я изучаю clojure и просто играю с атомами и реферами.Вот простая реализация дерева, но она вызывает переполнение стека при выполнении метода 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 до child2 работает, но сброс его в root вызывает переполнение стека.Можете ли вы помочь мне понять, почему?

1 Ответ

12 голосов
/ 22 апреля 2011

На самом деле это не reset!, а REPL, пытающийся напечатать (бесконечно) вложенные значения.

Попробуйте это:

(set! *print-level* 10)

Это ограничит рекурсивную печать иерархических объектов.

...