web-dev-qa-db-fra.com

Différence entre doseq et for à Clojure

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

99
Jeff the Bear

La différence est que for construit une séquence paresseuse et la renvoie tandis que doseq sert à exécuter les 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 souhaitez effectuer 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.

159
Rayne

Notez également que doseq est impatient tandis que for est 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, ce qui provoque les impressions. environnement non interactif, rien ne sera jamais imprimé. Vous pouvez le voir 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

Étant donné que le formulaire def renvoie le nouveau var créé, et non la valeur qui lui est liée, il n'y a rien pour le REPL à imprimer et lazy sera fait référence à un lazy-seq non réalisé: aucun de ses éléments n'a été calculé du tout. eager fera référence à nil, et toute son impression aura été effectuée.

56
amalloy