Diferencia entre doseq y for en Clojure

105

¿Cuál es la diferencia entre doseq y for en Clojure? ¿Cuáles son algunos ejemplos de cuándo elegiría usar uno sobre el otro?

Jeff el oso
fuente

Respuestas:

167

La diferencia es que forcrea una secuencia diferida y la devuelve mientras doseqes para ejecutar efectos secundarios y devuelve 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

Si desea crear una nueva secuencia basada en otras secuencias, use for. Si desea hacer efectos secundarios (imprimir, escribir en una base de datos, lanzar una ojiva nuclear, etc.) basados ​​en elementos de algunas secuencias, use doseq.

Rayne
fuente
11
ahora que son muchos efectos secundarios ... lanzamiento de una ojiva nuclear :)
Marc
6
¡Gracias! Me estaba tirando del pelo (desaparecido hace mucho tiempo) con "para" que nunca disparara mis ojivas nucleares sobre mi lista de artículos. "doseq" seguro que lo hizo.
Yu Shen
Esta es una excelente manera de poner la distinción.
jskulski
60

Tenga en cuenta también que doseqestá ansioso mientras que fores perezoso. El ejemplo que falta en la respuesta de Rayne es

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

En el REPL, esto generalmente hará lo que quieras, pero eso es básicamente una coincidencia: el REPL fuerza la secuencia perezosa producida por for, lo que hace que suceda la impresión. En un entorno no interactivo, nunca se imprimirá nada. Puede ver esto en acción comparando los 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

Debido a que el defformulario devuelve la nueva var creada, y no el valor que está vinculado a ella, no hay nada para que el REPL imprima y lazyse referirá a un lazy-seq no realizado: ninguno de sus elementos se ha calculado en absoluto. eagerse referirá nil, y se habrá realizado toda su impresión.

amalloy
fuente
¿Cómo maneja doseq la evaluación de la secuencia perezosa infinita? ¿mala idea? llamarlo solo en secuencias finitas, ya sea ansioso o perezoso?
johnbakers
@johnbakers Se bloqueará para siempre hasta que se interrumpa la evaluación. Clojure nunca intenta manejar secuencias infinitas de una manera diferente a las secuencias finitas.
Radon Rosborough