РЕДАКТИРОВАТЬ: ВСЕ, ЧТО Я ПИСАЛ, НЕПРАВИЛЬНО
Когда к функции с var-arg применяется значение seq, превышающее число дискретных аргументов, остаток seq передается как var-arg (см. RestFn.applyTo ).
Юргену: Я тупой. Ты умный. Я был неправ. Ты был прав. Ты лучший. Я худший Вы очень хорошо выглядите. Я не привлекательный.
Ниже приведена запись моего идиотизма ...
<Ч />
Ответ на комментарий Юргена Хётцеля.
mapcat
не является полностью ленивым, потому что apply
не ленив в оценке количества применяемых аргументов. Кроме того, apply
не может быть ленивым, потому что функции должны вызываться с дискретным числом аргументов. В настоящее время, если количество аргументов превышает 20, остальные аргументы сбрасываются в массив, поэтому они не ленивые.
Итак, глядя на источник для 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)))
Если мы расширим оценку, используя пример, внутренний apply
будет иметь оценку:
user=> (map seq str-coll)
((\a \b \c \d) (\e \f \g \h) (\j \k \l \m))
, что хорошо, так как str-coll
не полностью реализован, но тогда внешний apply
оценивается как:
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)
Обратите внимание, что внешние apply
применяют n аргументов к concat
, по одному для каждой строки в исходном str-coll
. Теперь верно, что результат concat
является ленивым, и каждый аргумент сам по себе ленив, но вам все равно нужно реализовать полную длину str-coll
, чтобы получить эти n ленивые последовательности. Если str-coll
имеет 1000 строк, то concat
получит 1000 аргументов, и все 1000 строк необходимо будет прочитать из файла и в память, прежде чем можно будет вызвать concat
.
<Ч />
Для неверующих, демонстрация seq-реализующего поведения apply:
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
И демонстрация того, что варарги не ленивы:
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
Хотя в качестве контрапункта меня смущает следующее:
user=> (take 10 (apply concat (repeat [1 2 3 4])))
(1 2 3 4 1 2 3 4 1 2)