"for"在clojure中实际上是不是很懒惰?

Ste*_*gle 15 list-comprehension clojure lazy-evaluation

(take 2 (for [x (range 10)
              :let [_ (println x)]
              :when (even? x)] x))
>> (* 0
* 1
* 2
* 3
* 4
* 5
* 6
* 7
* 8
* 9
0 2)
Run Code Online (Sandbox Code Playgroud)

我以为我只是非常密集.但不是,事实证明Clojure实际上评估了任何延迟序列的前32个元素(如果可用).哎哟.

我有一个for递归电话:let.我很好奇为什么计算似乎是先进行广泛而不是深度优先.似乎计算(尽管,公平,不是内存)正在爆炸,因为我一直在递归树的所有上部分支.虽然代码的逻辑意图是深度优先的,但Clojure的32分块正在强制进行广泛的第一次评估.

无论如何,有没有简单的方法来强制1分块而不是32分块的懒惰序列?

Cha*_*ffy 13

Michaes Fogus 撰写了一篇关于通过提供自定义ISeq实现来禁用此行为的博客条目.

Colin Jones的修改版本中无耻地窃取:

(defn seq1 [#^clojure.lang.ISeq s]
  (reify clojure.lang.ISeq
    (first [_] (.first s))
    (more [_] (seq1 (.more s)))
    (next [_] (let [sn (.next s)] (and sn (seq1 sn))))
    (seq [_] (let [ss (.seq s)] (and ss (seq1 ss))))
    (count [_] (.count s))
    (cons [_ o] (.cons s o))
    (empty [_] (.empty s))
    (equiv [_ o] (.equiv s o))))
Run Code Online (Sandbox Code Playgroud)

在"欢乐的Clojure"中给出一种更简单的方法:

(defn seq1 [s]
  (lazy-seq
    (when-let [[x] (seq s)]
       (cons x (seq1 (rest s))))))
Run Code Online (Sandbox Code Playgroud)