Must Clojure circular data structures involve constructs like ref?

谁说胖子不能爱 提交于 2019-12-19 07:38:14

问题


Today I've seen some references to tying the knot and circular data structures. I've been out reading some answers, and the solutions seem to involve using a ref to point back to the head of the list. One particular SO question showed a Haskell example, but I don't know Haskell well enough to know if the example was using a the Haskell equivalent of a ref.

Is there a way to make a Clojure data structure circular without using a ref or similar construct?

Thanks.


回答1:


I straightforwardly translated the Haskell example into Clojure:

user> (def alternates
          (letfn [(x [] (lazy-seq (cons 0 (y))))
                  (y [] (lazy-seq (cons 1 (x))))]
            (x)))
#'user/alternates
user> (take 7 alternates)
(0 1 0 1 0 1 0)

It works as expected. However I prefer the cycle function to mutually recursive functions using letfn:

user> (take 7 (cycle [0 1]))
(0 1 0 1 0 1 0)



回答2:


It's impossible to create a circular reference using the standard Clojure immutable data structures and standard Clojure functions. This is because whichever object is created second can never be added to the (immutable) object which is created first.

However there are are multiple ways that you can create a circular data structure if you are willing to use a bit of trickery:

  • Refs, atoms etc.
  • Mutable deftypes
  • Java objects
  • Reflection trickery
  • Lazy sequences

In general however, circular data structures are best avoided in Clojure.




回答3:


I've used this before:

;; circular list operations
(defn rotate
   ([cl] (conj (into [](rest cl)) (first cl)))
   ([cl n] (nth (iterate rotate cl) (mod n (count cl)))))

The output is a vector but the input can be any sequence.



来源:https://stackoverflow.com/questions/11568036/must-clojure-circular-data-structures-involve-constructs-like-ref

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!