EDIT: tutto quello che ho scritto è stato sbagliato
Quando una funzione con un var-arg viene applicato a un seq più lungo del numero di argomenti discreti, il resto del seq viene passato come var-arg (vedere RestFn.applyTo).
A Jürgen: Sono stupido. Sei intelligente. Mi sbagliavo. Avevi ragione. Sei il migliore. Sono il peggiore. Sei molto bello. Non sono attraente
La seguente è una traccia della mia idiozia ...
risposta al commento di Jürgen Hötzel.
mapcat
non è completamente pigro perché apply
non è pigro nel valutare il numero di argomenti da applicare. Inoltre, apply
non può essere pigro perché le funzioni devono essere invocate con un numero discreto di argomenti. Attualmente se il numero di args supera 20, gli argomenti rimanenti vengono scaricati in un array, quindi non pigri.
Così guardando la fonte per mapcat
:
(defn mapcat
"Returns the result of applying concat to the result of applying map
to f and colls. Thus function f should return a collection."
{:added "1.0"}
[f & colls]
(apply concat (apply map f colls)))
Se ci espandiamo la valutazione utilizzando l'esempio, l'interno apply
sarebbe valutato come:
user=> (map seq str-coll)
((\a \b \c \d) (\e \f \g \h) (\j \k \l \m))
che va bene in quanto i str-coll
doesn essere pienamente realizzato, ma poi l'esterno apply
valuterebbe:
user=> (concat '(\a \b \c \d) '(\e \f \g \h) '(\j \k \l \m))
(\a \b \c \d \e \f \g \h \j \k \l \m)
Si noti che l'esterno apply
applica n argomenti a concat
, uno per ogni stringa nell'originale str-coll
. Ora, è vero che il risultato di concat
è pigro, e ogni argomento è esso stesso pigro, ma è comunque necessario realizzare l'intera lunghezza di n lazy seqs. Se str-coll
ha 1000 stringhe, allora concat
otterrà 1000 arg e tutte le stringhe 1000 dovranno essere lette dal file e in memoria prima che sia possibile chiamare concat
.
Per The Unbelievers, una dimostrazione del comportamento seq-realizzativa applica:
user=> (defn loud-seq [] (lazy-seq (println "HELLO") (cons 1 (loud-seq))))
#'user/loud-seq
user=> (take 3 (loud-seq)) ; displaying the lazy-seq realizes it, thus printing HELLO
(HELLO
HELLO
1 HELLO
1 1)
user=> (do (take 3 (loud-seq)) nil) ; lazy-seq not realized; no printing of HELLO
nil
user=> (do (apply concat (take 3 (loud-seq))) nil) ; draw your own conclusions
HELLO
HELLO
HELLO
nil
E una dimostrazione che varargs non sono pigri:
user=> (defn foo [& more] (type more))
#'user/foo
user=> (foo 1 2 3 4)
clojure.lang.ArraySeq
user=> (apply foo (repeat 4 1))
clojure.lang.Cons
Sebbene come contrappunto, che i seguenti lavori mi sconcertano:
user=> (take 10 (apply concat (repeat [1 2 3 4])))
(1 2 3 4 1 2 3 4 1 2)
Non c'è bisogno di appiattire, basta concatenare le sequenze di caratteri usando mapcat: (partition-all 3 (mapcat seq str-coll)) –
ataggart e Jürgen, grazie mille per le soluzioni: mappare a un seq era esattamente quello che ero mancante. Superare quell'ostacolo mi portò a realizzare che partizione non agiva pigramente come speravo. Mentre ogni partizione viene fornita in modo lazy, i singoli componenti di ogni partizione non lo sono; quindi il partizionamento del file iniziale ai delimitatori non fornisce le stringhe pigro desiderate che si alimentano in questo. –
@ Jürgen: mapcat non è pigro (usa apply), quindi perché non l'ho usato. –