2012-05-11 17 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) 

Supponevo che stavo solo incredibilmente denso. Ma no, si scopre che Clojure valuta effettivamente i primi 32 elementi di ogni sequenza pigra (se disponibile). Ahia.È "per" non effettivamente pigro in clojure?

Ho avuto un for con una chiamata ricorsiva nel :let. Ero molto curioso sul motivo per cui il computo sembrava procedere in prima battuta piuttosto che in prima approssimazione. Sembra che il calcolo (anche se, per essere onesto, non memoria) stava esplodendo mentre continuavo a scendere tutti i rami superiori dell'albero ricorsivo. Il 32-Chunking di Clojure stava forzando la prima valutazione di ampiezza, anche se l'intento logico del codice era prima la profondità.

In ogni caso, c'è un modo semplice per forzare 1-chunking piuttosto che 32-chunking di sequenze pigre?

risposta

13

Michaes Fogus has written a blog entry on disabling this behavior by providing a custom ISeq implementation.

di rubare spudoratamente da 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)))) 

Un approccio più semplice è dato in The Joy of Clojure:

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

Grazie! Questo mi ha lasciato per due ore. Non sono riuscito a capire perché (prendi 1 (map-func [1 2 3 4])) valuta some-func per tutti i 4 elementi ... Devo dire, non era ovvio perché ciò stava accadendo, dalla lettura dei documenti su "mappa" e "prendere" –

3

Per rispondere alla domanda nel titolo, no, for non è pigro. However, esso:

prende un vettore di coppie uno o più -forma vincolante/collezione-espr, ciascuno seguito da zero o più modificatori e produce una sequenza artificiale di valutazioni di expr.

(sottolineatura mia)

Così what's going on?

fondamentalmente Clojure valuta sempre rigorosamente. Lazy seqs fondamentalmente usa gli stessi trucchi di Python con i loro generatori, ecc. Evals rigorosi in abiti pigri.

In altre parole, foravidamente restituisce un pigro sequenza. Che non sarà valutato fino a quando non lo chiedi e sarà squartato.

Problemi correlati