Różnica między dawkaq a for w Clojure

105

Jaka jest różnica między Doseq a For w Clojure? Jakie są przykłady, kiedy zdecydowałbyś się użyć jednego nad drugim?

Jeff the Bear
źródło

Odpowiedzi:

167

Różnica polega na tym, że forbuduje leniwą sekwencję i zwraca ją, podczas gdy doseqsłuży do wykonywania efektów ubocznych i zwraca 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

Jeśli chcesz zbudować nową sekwencję na podstawie innych sekwencji, użyj for. Jeśli chcesz zrobić efekty uboczne (drukowanie, zapis do bazy danych, wystrzelenie głowicy nuklearnej itp.) W oparciu o elementy z niektórych sekwencji, użyj dawkiq.

Rayne
źródło
11
teraz jest dużo skutków ubocznych ... wystrzelenie głowicy nuklearnej :)
Marc
6
Dzięki! Ciągnąłem moje (dawno nieobecne) włosy z „za”, że nigdy nie wystrzeliwują moich głowic nuklearnych nad moją listą pozycji. „Doseq” z pewnością tak.
Yu Shen
To świetny sposób na wyróżnienie.
jskulski
60

Zauważ również, że doseqjest chętny, gdy forjest leniwy. Przykład, którego brakuje w odpowiedzi Rayne'a to

(for [x [1 2 3]] (println x))

W REPL generalnie zrobi to, co chcesz, ale to w zasadzie zbieg okoliczności: REPL wymusza leniwą sekwencję wytworzoną przez for, powodując wystąpienie printlns. W środowisku nieinteraktywnym nic nigdy nie zostanie wydrukowane. Możesz to zobaczyć w akcji, porównując wyniki

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

Ponieważ defformularz zwraca nowo utworzoną zmienną, a nie wartość, która jest z nią związana, REPL nie ma nic do wydrukowania i lazybędzie odnosić się do niezrealizowanej sekwencji leniwej: żaden z jej elementów nie został w ogóle obliczony. eagerbędzie odnosić się nil, a wszystkie jego wydruki zostaną wykonane.

amaloy
źródło
Jak Doseq radzi sobie z oceną nieskończonej leniwej sekwencji? kiepski pomysł? nazywać to tylko skończonymi sekwencjami, albo chętnymi, albo leniwymi?
johnbakers
@johnbakers Będzie blokować się na zawsze, dopóki ocena nie zostanie przerwana. Clojure nigdy nie próbuje obsłużyć nieskończonych sekwencji w inny sposób niż skończone sekwencje.
Radon Rosborough