Diferença entre doseq e para em Clojure

105

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?

Jeff the Bear
fonte

Respostas:

167

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.

Rayne
fonte
11
agora que são muito mais efeitos colaterais ... lançar uma ogiva nuclear :)
Marc
6
Obrigado! Eu estava puxando meu cabelo (desaparecido) com "para" que nunca dispararia minhas ogivas nucleares sobre a minha lista de itens. "doseq" com certeza.
Yu Shen de
Esta é uma ótima maneira de fazer a distinção.
jskulski
60

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.

amalloy
fonte
Como o doseq lida com a avaliação da sequência preguiçosa infinita? péssima ideia? apenas chamá-lo em sequências finitas, ansioso ou preguiçoso?
johnbakers
@johnbakers Bloqueará para sempre até que a avaliação seja interrompida. Clojure nunca tenta lidar com sequências infinitas de uma maneira diferente das sequências finitas.
Radon Rosborough