#clojure
#clojure
Вопрос:
Зачем требуется оболочка lazy-cons? Есть две функции с одинаковым результатом.
(defn seq1 [s]
(lazy-seq
(when-let [x (seq s)]
(cons (first x) (seq1 (rest x))))))
(defn seq2 [s]
(when-let [x (seq s)]
(cons (first x) (seq2 (rest x)))))
В обоих случаях я получил тот же результат, что и без фрагментированных последовательностей.
repl.core=> (first (map println (seq1 (range 1000))))
0
nil
repl.core=> (first (map println (seq2 (range 1000))))
0
nil
repl.core=> (chunked-seq? (seq2 (range 1000)))
false
repl.core=> (chunked-seq? (seq1 (range 1000)))
false
Комментарии:
1. Вы можете прочитать больше здесь: braveclojure.com/core-functions-in-depth
Ответ №1:
Первый — ленивый. Он оценивает элементы последовательности только по мере необходимости. Второй, однако, является строгим и проходит через всю последовательность немедленно. Это можно увидеть, если добавить несколько println
вызовов в каждый:
(defn seq1 [s]
(lazy-seq
(when-let [x (seq s)]
(println "Seq1" (first x))
(cons (first x) (seq1 (rest x))))))
(defn seq2 [s]
(when-let [x (seq s)]
(println "Seq2" (first x))
(cons (first x) (seq2 (rest x)))))
(->> (range 10)
(seq1)
(take 5))
Seq1 0
Seq1 1
Seq1 2
Seq1 3
Seq1 4 ; Only iterated over what was asked for
=> (0 1 2 3 4)
(->> (range 10)
(seq2)
(take 5))
Seq2 0
Seq2 1
Seq2 2
Seq2 3
Seq2 4
Seq2 5
Seq2 6
Seq2 7
Seq2 8
Seq2 9 ; Iterated over everything immediately
=> (0 1 2 3 4)
Итак, чтобы ответить на вопрос, lazy-seq
требуется только в том случае, если вы намерены выполнять итерацию последовательности только по мере необходимости. Предпочитайте отложенные решения, если вы считаете, что вам может не понадобиться вся последовательность, или последовательность бесконечна, или вы хотите выполнить несколько преобразований, используя map
или filter
. Используйте строгое решение, если в какой-то момент вам, вероятно, понадобится вся последовательность и / или вам нужен быстрый произвольный доступ.