Qual é a diferença entre doseq e for em Clojure? Quais são alguns exemplos de quando você escolheria usar um em vez do outro?
Qual é a diferença entre doseq e for em Clojure? Quais são alguns exemplos de quando você escolheria usar um em vez do outro?
Respostas:
A diferença é que for
cria uma sequência preguiçosa e a retorna enquanto doseq
é para a execução de efeitos colaterais e retorna nulo.
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
Se você deseja construir uma nova sequência baseada em outras sequências, use para. Se você quiser fazer efeitos colaterais (imprimir, gravar em um banco de dados, lançar uma ogiva nuclear, etc.) com base em elementos de algumas sequências, use o doseq.
Observe também que doseq
é ansioso enquanto for
é preguiçoso. O exemplo que falta na resposta de Rayne é
(for [x [1 2 3]] (println x))
No REPL, isso geralmente fará o que você quiser, mas isso é basicamente uma coincidência: o REPL força a sequência preguiçosa produzida por for
, fazendo com que as impressões aconteçam. Em um ambiente não interativo, nada será impresso. Você pode ver isso em ação comparando os resultados de
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
Como o def
formulário retorna a nova var criada, e não o valor que está vinculado a ela, não há nada para o REPL imprimir e lazy
se referirá a um lazy-seq não realizado: nenhum de seus elementos foi calculado. eager
irá se referir a nil
, e todas as suas impressões terão sido feitas.