Разница между DoSq и For в Clojure


106

В чем разница между DoSq и for в Clojure? Каковы примеры того, когда вы бы предпочли использовать одно вместо другого?

Ответы:


168

Разница в том, что forстроит ленивую последовательность и возвращает ее, а doseqпредназначена для выполнения побочных эффектов и возвращает nil.

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

Если вы хотите создать новую последовательность на основе других последовательностей, используйте for. Если вы хотите создать побочные эффекты (печать, запись в базу данных, запуск ядерной боеголовки и т. Д.) На основе элементов из некоторых последовательностей, используйте дозу.


11
теперь это много побочных эффектов ... запуск ядерной боеголовки :)
— Marc

6
Спасибо! Я тянул свои (давно пропавшие) волосы «за», чтобы они никогда не запускали мои ядерные боеголовки поверх моего списка предметов. "Doseq", конечно, сделал.
— Yu Shen

Это отличный способ провести различие.
— jskulski

60

Также обратите внимание, что doseqлюбит, когда forленится. Пример, отсутствующий в ответе Рейна:

(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форма возвращает созданную новую переменную, а не значение, которое к ней привязано, REPL нечего печатать и lazyбудет ссылаться на нереализованный lazy-seq: ни один из его элементов не был вычислен вообще. eagerбудет ссылаться на nil, и вся его печать будет выполнена.


Как DoSq обрабатывает оценку бесконечной ленивой последовательности? плохая идея? называть это только конечными последовательностями, нетерпеливыми или ленивыми?
— johnbakers

@johnbakers Он будет заблокирован навсегда, пока оценка не будет прервана. Clojure никогда не пытается обрабатывать бесконечные последовательности иначе, чем конечные последовательности.
— Radon Rosborough
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.