Clojure的循环数据结构是否需要像ref这样的构造?

5
今天我看到了一些关于“tying the knot”和循环数据结构的参考资料。我读了一些答案,这些解决方案似乎涉及使用一个引用指向列表头部。一个特定的 SO问题展示了一个Haskell示例,但我不太了解Haskell,不知道该示例是否使用了Haskell等效的引用。有没有一种方法可以使Clojure数据结构循环而不使用ref或类似的构造?谢谢。

你难道不是在复制我在 https://dev59.com/WWbWa4cB1Zd3GeqPVVHT 上所问的问题吗? - andrew cooke
3个回答

7

我直接将Haskell的例子翻译成了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)

它按预期工作。然而,我更喜欢使用cycle函数而不是使用letfn相互递归的函数:

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

6

使用标准的Clojure不可变数据结构和标准的Clojure函数,无法创建循环引用。这是因为第二个创建的对象永远无法添加到先创建的(不可变)对象中。

但是,如果您愿意使用一些技巧,有多种方法可以创建循环数据结构:

  • Refs、atoms等
  • 可变deftypes
  • Java对象
  • 反射技巧
  • 延迟序列

然而,在Clojure中,通常最好避免使用循环数据结构。


3

我以前用过这个:

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

输出是一个向量,但输入可以是任何序列。

我需要考虑一下,但这是否适用于我的问题:https://dev59.com/WWbWa4cB1Zd3GeqPVVHT(谢谢)? - andrew cooke
@andrewcooke 我发布了这个问题是因为你的问题。它不是你问题的副本,而是针对Clojure的特定问题。 - octopusgrabbus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接