Differenza tra doseq e for in Clojure


105

Qual è la differenza tra doseq e for in Clojure? Quali sono alcuni esempi di quando sceglieresti di usarne uno sull'altro?

Risposte:


167

La differenza è che forcostruisce una sequenza pigra e la restituisce mentre doseqè per l'esecuzione di effetti collaterali e restituisce zero.

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 vuoi costruire una nuova sequenza basata su altre sequenze, usa per. Se vuoi creare effetti collaterali (stampa, scrittura su un database, lancio di una testata nucleare, ecc.) Basati su elementi di alcune sequenze, usa doseq.


11
ora che sono molti effetti collaterali ... lancio di una testata nucleare :)
Marc

6
Grazie! Mi ero tirato i capelli (ormai da tempo) con "per" che non spara mai le mie testate nucleari sulla mia lista di oggetti. "doseq" sicuramente lo ha fatto.
Yu Shen

Questo è un ottimo modo per porre la distinzione.
jskulski

60

Nota anche che doseqè desideroso mentre forè pigro. L'esempio che manca nella risposta di Rayne è

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

Al REPL, questo generalmente farà quello che vuoi, ma è fondamentalmente una coincidenza: il REPL forza la sequenza pigra prodotta da for, provocando la stampa. In un ambiente non interattivo, non verrà mai stampato nulla. Puoi vederlo in azione confrontando i risultati di

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

Poiché il defmodulo restituisce la nuova var creata e non il valore ad essa associato, non c'è nulla da stampare per REPL e lazyfarà riferimento a un lazy-seq non realizzato: nessuno dei suoi elementi è stato calcolato affatto. eagerfarà riferimento a nil, e tutta la stampa sarà stata eseguita.


In che modo doseq gestisce la valutazione della sequenza pigra infinita? cattiva idea? chiamarlo solo su sequenze finite, vogliose o pigre?
johnbakers

@johnbakers Si bloccherà per sempre fino a quando la valutazione non verrà interrotta. Clojure non tenta mai di gestire sequenze infinite in modo diverso dalle sequenze finite.
Radon Rosborough
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.