2012-05-11 43 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熱切返回懶惰序列。直到你要求它纔會被評估,並且會被分塊。