Perbedaan antara dosisq dan untuk di Clojure

105

Apa perbedaan antara doseq dan untuk di Clojure? Apa saja contoh ketika Anda akan memilih untuk menggunakan salah satu dari yang lain?

Jeff si Beruang
sumber

Jawaban:

167

Perbedaannya adalah bahwa formembangun urutan malas dan mengembalikannya saat dosequntuk menjalankan efek samping dan mengembalikan nol.

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

Jika Anda ingin membuat urutan baru berdasarkan urutan lain, gunakan untuk. Jika Anda ingin melakukan efek samping (mencetak, menulis ke database, meluncurkan hulu ledak nuklir, dll) berdasarkan elemen dari beberapa urutan, gunakan doseq.

Rayne
sumber
11
sekarang yang jauh efek samping ... meluncurkan hulu ledak nuklir :)
Marc
6
Terima kasih! Saya telah menarik rambut saya (yang sudah lama hilang) dengan kata "untuk" bahwa itu tidak pernah menembakkan hulu ledak nuklir saya ke daftar item saya. "doseq" pasti melakukannya.
Yu Shen
Ini adalah cara yang bagus untuk membedakan.
jskulski
60

Perhatikan juga yang doseqbersemangat saat forsedang malas. Contoh yang hilang dalam jawaban Rayne adalah

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

Di REPL, ini biasanya akan melakukan apa yang Anda inginkan, tetapi itu pada dasarnya kebetulan: REPL memaksa urutan malas yang dihasilkan oleh for, menyebabkan printlns terjadi. Dalam lingkungan non-interaktif, tidak ada yang akan dicetak. Anda dapat melihat ini beraksi dengan membandingkan hasil

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

Karena defformulir mengembalikan var baru yang dibuat, dan bukan nilai yang terikat padanya, REPL tidak akan mencetak apa pun, dan lazyakan merujuk ke lazy-seq yang belum direalisasi: tidak ada elemennya yang telah dihitung sama sekali. eagerakan merujuk ke nil, dan semua pencetakannya akan selesai.

amalloy
sumber
Bagaimana doseq menangani evaluasi urutan malas tak terbatas? ide buruk? hanya menyebutnya pada urutan yang terbatas, entah bersemangat atau malas?
johnbakers
@johnbakers Ini akan memblokir selamanya sampai evaluasi dihentikan. Clojure tidak pernah mencoba menangani urutan tak terbatas dengan cara yang berbeda dari urutan terbatas.
Radon Rosborough