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 forcria 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 defformulá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 lazyse referirá a um lazy-seq não realizado: nenhum de seus elementos foi calculado. eagerirá se referir a nil, e todas as suas impressões terão sido feitas.