clojure - 'for' 在 clojure 中实际上不是懒惰的吗?

标签 clojure list-comprehension 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)

我以为我只是太笨了。但事实并非如此,事实证明 Clojure 实际上会计算任何惰性序列(如果可用)的前 32 个元素。哎哟。

我在 :let 中有一个带有递归调用的 for 。我很好奇为什么计算似乎是以广度优先而不是深度优先的方式进行的。当我不断沿着递归树的所有上部分支向下移动时,计算(尽管公平地说,不是内存)似乎呈爆炸式增长。 Clojure 的 32 分块强制进行广度优先评估,尽管代码的逻辑意图是深度优先。

无论如何,有什么简单的方法可以强制惰性序列进行 1 block 而不是 32 block 吗?

最佳答案

迈克尔·福格斯 has written a blog entry on disabling this behavior by providing a custom ISeq implementation .

无耻地窃取the modified version by 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))))

给出了更简单的方法in The Joy of Clojure :

(defn seq1 [s]
  (lazy-seq
    (when-let [[x] (seq s)]
       (cons x (seq1 (rest s))))))

关于clojure - 'for' 在 clojure 中实际上不是懒惰的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10556421/

相关文章:

lambda - 线程宏 -> 带有匿名函数

python - 使用列表理解来标记两个列表共有的数据

python - 当列表为空时列表理解抛出异常

Python:在理解中重复函数调用的更好解决方案

haskell - peekCString 和 peekCStringLen 是懒惰的吗?

python - 如何在 Python 中动态添加一个类方法

clojure - 在 Clojure 中声明匿名函数是否很昂贵?

import - 我无法在 clojure/midje 中运行测试

mysql - 如何从 Clojure 连接到 MySQL 数据库?

F# PSeq.iter 似乎没有使用所有内核