在Clojure For Comprehension example的答案中,我有一个处理自己输出的函数:
(defn stream [seed]
(defn helper [slow]
(concat (map #(str (first slow) %) seed) (lazy-seq (helper (rest slow)))))
(declare delayed)
(let [slow (cons "" (lazy-seq delayed))]
(def delayed (helper slow))
delayed))
(take 25 (stream ["a" "b" "c"]))
("a" "b" "c" "aa" "ab" "ac" "ba" "bb" "bc" "ca" "cb" "cc" "aaa" "aab" "aac"
"aba" "abb" "abc" "aca" "acb" "acc" "baa" "bab" "bac" "bba")
它的工作原理是创建一个前向引用(delayed
),它用作延迟序列(slow
)中的第二个条目。该序列被传递给该函数,该函数是惰性的,并且该函数的输出(惰性序列的第一部分,其不需要评估delayed
)然后用于设置{的值。 {1}}。
通过这种方式我“打结”。但这在Haskell中更优雅(例如Explanation of “tying the knot”)。鉴于Clojure有delayed
和delay
,我想知道是否有更好的方法来完成上述工作?
那么问题:在上面的代码中可以以某种方式避免(丑陋的,明确的)突变(force
)吗?显然(?)你仍然需要变异,但它可以被“懒惰”构造隐藏吗?
[当我还在努力了解如何做到这一点时,我昨晚有一个类似标题的问题;在上面的代码工作之前没有人回复,所以我删除了它,但我对这种方法并不满意,所以我再试一次。]
另见:Must Clojure circular data structures involve constructs like ref?(有点令人沮丧的是人们在复制问题)。
答案 0 :(得分:2)
我不确定我是否可以回答一般情况的问题,但这个功能似乎解决了特定情况。
(defn stream
[seed]
(let [step (fn [prev] (for [p prev s seed] (str p s)))]
(for [x (iterate step seed) y x] y)))
虽然我遇到了大(dorun (take ...))
的内存不足异常。所以这个功能可能存在问题。