2012-05-11 59 views
15
(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个元素(如果可用)。哎哟。是不是真的懒惰在clojure?

我有一个for递归调用:let。我很好奇为什么计算似乎是先在广度上进行,而不是深度优先。看起来,计算(尽管公平,而不是记忆)正在爆炸,因为我一直沿着递归树的所有上层分支进行下去。尽管代码的逻辑意图是深度优先,但Clojure的32分组迫使广度优先评估。

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

回答

13

Michaes Fogus 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)))))) 
+0

谢谢!这让我陷入了两个小时。我想不通为什么 (拿1(map some-func [1 2 3 4])) 评估所有4个元素的some-func ...我必须说,这并不是明显的原因,从阅读“地图”和“采取”文档 –

3

要回答你的标题问题,没有,for更是不可以偷懒。 However,它:

注意到一个或多个 结合型/收集-EXPR对的矢量,每个随后的零个或更多 改性剂和产生expr的评价的懒惰序列。

(重点煤矿)

所以what's going on

基本上Clojure总是严格评估。懒惰seqs 基本上使用相同的技巧蟒蛇与他们的发电机等 严格的evals在懒衣服。

换句话说,for热切返回懒惰序列。直到你要求它才会被评估,并且会被分块。