Jaka jest różnica między Doseq a For w Clojure? Jakie są przykłady, kiedy zdecydowałbyś się użyć jednego nad drugim?
Jaka jest różnica między Doseq a For w Clojure? Jakie są przykłady, kiedy zdecydowałbyś się użyć jednego nad drugim?
Odpowiedzi:
Różnica polega na tym, że for
buduje leniwą sekwencję i zwraca ją, podczas gdy doseq
sł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.
Zauważ również, że doseq
jest chętny, gdy for
jest 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ż def
formularz zwraca nowo utworzoną zmienną, a nie wartość, która jest z nią związana, REPL nie ma nic do wydrukowania i lazy
będzie odnosić się do niezrealizowanej sekwencji leniwej: żaden z jej elementów nie został w ogóle obliczony. eager
będzie odnosić się nil
, a wszystkie jego wydruki zostaną wykonane.