Différence entre doseq et for dans Clojure

105

Quelle est la différence entre doseq et for in Clojure? Quels sont quelques exemples de cas où vous choisiriez d'utiliser l'un plutôt que l'autre?

Jeff l'ours
la source

Réponses:

167

La différence est que forconstruit une séquence paresseuse et la renvoie tandis que doseqc'est pour exécuter des effets secondaires et renvoie 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 vous souhaitez créer une nouvelle séquence basée sur d'autres séquences, utilisez pour. Si vous voulez faire des effets secondaires (impression, écriture dans une base de données, lancement d'une ogive nucléaire, etc.) basés sur des éléments de certaines séquences, utilisez doseq.

Rayne
la source
11
maintenant il y a beaucoup d'effets secondaires ... lancer une ogive nucléaire :)
Marc
6
Merci! J'avais tiré mes cheveux (partis depuis longtemps) avec "pour" qu'il ne tire jamais mes ogives nucléaires sur ma liste d'articles. "doseq" bien sûr.
Yu Shen
C'est une excellente façon de faire la distinction.
jskulski
60

Notez également qu'il doseqest impatient pendant qu'il forest paresseux. L'exemple manquant dans la réponse de Rayne est

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

Au REPL, cela fera généralement ce que vous voulez, mais c'est essentiellement une coïncidence: le REPL force la séquence paresseuse produite par for, provoquant l'apparition des printlns. Dans un environnement non interactif, rien ne sera jamais imprimé. Vous pouvez voir cela en action en comparant les résultats 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

Parce que le defformulaire renvoie la nouvelle var créée, et non la valeur qui lui est liée, il n'y a rien à afficher pour le REPL, et lazyse référera à un lazy-seq non réalisé: aucun de ses éléments n'a été calculé du tout. eagerfera référence à nil, et toute son impression aura été effectuée.

amalloy
la source
Comment doseq gère-t-il l'évaluation d'une séquence paresseuse infinie? mauvaise idée? ne l'appeler que sur des séquences finies, impatientes ou paresseuses?
johnbakers
@johnbakers Il sera bloqué pour toujours jusqu'à ce que l'évaluation soit interrompue. Clojure ne tente jamais de gérer des séquences infinies d'une manière différente des séquences finies.
Radon Rosborough