Какая разница между дозой и в Clojure? Каковы некоторые примеры того, когда вы решили использовать один над другим?
Разница между дозой и в Clojure
Ответ 1
Разница в том, что for
создает ленивую последовательность и возвращает ее, а doseq
- для выполнения побочных эффектов и возвращает нуль.
user=> (for [x [1 2 3]] (+ x 5))
(6 7 8)
user=> (doseq [x [1 2 3]] (+ x 5))
nil
user=> (doseq [x [1 2 3]] (println x))
1
2
3
nil
Если вы хотите создать новую последовательность, основанную на других последовательностях, используйте для. Если вы хотите делать побочные эффекты (печать, запись в базу данных, запуск ядерной боеголовки и т.д.) На основе элементов из некоторых последовательностей, используйте дозу.
Ответ 2
Обратите внимание, что doseq
нетерпелив, а for
- ленив. В примере, отсутствующем в ответе Rayne,
(for [x [1 2 3]] (println x))
В REPL это, как правило, будет делать то, что вы хотите, но это в основном совпадение: REPL заставляет ленивую последовательность, создаваемую for
, вызывая появление printlns. В неинтерактивной среде ничто никогда не будет напечатано. Вы можете увидеть это в действии, сравнив результаты
user> (def lazy (for [x [1 2 3]] (println 'lazy x)))
#'user/lazy
user> (def eager (doseq [x [1 2 3]] (println 'eager x)))
eager 1
eager 2
eager 3
#'user/eager
Поскольку форма def
возвращает новый созданный var, а не значение, которое привязано к нему, для печати REPL ничего не существует, а lazy
будет ссылаться на нереализованный lazy-seq: ни один из его элементов были рассчитаны вообще. eager
будет ссылаться на nil
, и вся его печать будет выполнена.