指针在clojure中循环

Gil*_*ans 8 pointers clojure immutability data-structures

我正在编写一个解析XML的clojure程序.作为其中的一部分,我希望基于clojure.xml/parse函数在XML文档中创建节点树.但是,我希望树是双向的 - 也就是说,每个节点都有一个子列表,以及指向其父节点的指针.只有一个问题:所有的数据是不变的,所以我不能一个指针"添加"到父不改变孩子,从而使母公司的指针没用.

我找到了这个答案:如何在没有额外间接的情况下在Clojure中创建循环(和不可变)数据结构?

解决方案建议似乎创建一个单独的索引映射,它引用内部的对象.对于更糟糕的解决方案来说,这似乎是一项巨大的工作.在构造过程中,树没有问题,但我无法弄清楚它是如何完成的.在clojure中真的没有办法获得循环指针吗?

谢谢!

mik*_*era 5

逻辑上不可能使纯不可变结构循环,因为通过添加父指针或子指针,您将改变结构.

虽然我不确定我会推荐它,但是有一个hack有效:你可以将原子放在Clojure数据结构中,然后改变它们以建立必要的链接.例如

(def parent {:id 1 :children (atom nil) :parent (atom nil)})

(def child  {:id 2 :children (atom nil) :parent (atom nil)}) 

(swap! (:children parent) conj child)
(reset! (:parent child) parent)

;; test it works
(:id @(:parent child))
=> 1
Run Code Online (Sandbox Code Playgroud)

这在各种方面都很讨厌:

  • 如果您尝试打印其中一个,它将导致您的REPL堆栈溢出,因为REPL不期望循环数据结构.
  • 它是可变的,所以你失去了不可变数据结构的所有可维护性和并发性好处(这是Clojure最好的东西之一!)
  • 如果要复制节点,则需要获取节点的完整副本(例如,构建新的XML文档),因为它不再是不可变的值.
  • 在导航结构时,解除引用所有原子可能会变得混乱.
  • 你会混淆那些惯用Clojure的人.

所以,如果你真的想要这样做是可能的.........虽然我个人认为如果你使你的文档表示正确不变,你在长远来看仍然会好得多.如果要导航结构,可以在文档中使用更像XPath样式位置的内容.

  • Clojure是一种非常"自以为是"的语言,强烈建议你沿着不可改变的路线前进.如果你想享受Clojure的全部优势,那么更好地接受它而不是打击它,我认为......从长远来看,我相信这种方法将帮助我们所有人制作出更好的软件. (2认同)