Cara mengonversi urutan malas menjadi non-malas di Clojure

95

Saya mencoba yang berikut di Clojure, mengharapkan kelas dari urutan non-malas dikembalikan:

(.getClass (doall (take 3 (repeatedly rand))))

Namun, ini masih kembali clojure.lang.LazySeq. Dugaan saya adalah itu doallmengevaluasi seluruh urutan, tetapi mengembalikan urutan asli karena masih berguna untuk memoization.

Jadi apa cara idiomatik untuk membuat urutan non-malas dari urutan malas?

Tim Clemons
sumber
Saya terkejut tidak ada yang bertanya mengapa Anda khawatir tentang jenis sebenarnya dari nilai pengembaliandoall
tar
Anda dapat mengonversi ke vektor:(vec (take 3 (repeatedly rand)))
Kris

Jawaban:

161

doalladalah semua yang Anda butuhkan. Hanya karena seqmemiliki tipe LazySeqtidak berarti memiliki evaluasi tertunda. Lazy seqs men-cache hasil mereka, jadi yang perlu Anda lakukan adalah menjalankan lazy seqsekali (seperti doallhalnya) untuk memaksakan semuanya, dan dengan demikian membuatnya tidak malas. seqtidak tidak memaksa seluruh koleksi untuk dievaluasi.

Cupang Kaya
sumber
2
Saya telah mengubah ini menjadi jawaban yang diterima. Pada catatan terkait, dengan cara apa Anda dapat menentukan apakah LazySeq sebelumnya telah dievaluasi?
Tim Clemons
10
Saya yakin Anda baru saja menelepon realized?.
toofarsideways
1
Mungkin harus ada realizeoperasi yang cocok realized?.
Reut Sharabani
Ini semua sangat bagus. Tetapi karena beberapa fungsi seperti contains?tidak peduli apakah Anda menyadari lazy seq atau tidak, ini menjawab pertanyaan spesifik seperti yang ditanyakan, tetapi kurang begitu untuk judul pertanyaan.
matanster
75

Ini sampai taraf tertentu merupakan pertanyaan tentang taksonomi. urutan malas hanyalah salah satu jenis urutan seperti daftar, vektor atau peta. Jadi jawabannya tentu saja "itu tergantung pada jenis urutan non lazy apa yang ingin Anda dapatkan:
Pilih dari:

  • urutan malas ex-lazy (dievaluasi sepenuhnya) (doall ... )
  • daftar untuk akses berurutan (apply list (my-lazy-seq)) OR (into () ...)
  • vektor untuk akses acak nanti (vec (my-lazy-seq))
  • peta atau set jika Anda memiliki tujuan khusus.

Anda dapat memiliki jenis urutan apa pun yang paling sesuai dengan kebutuhan Anda.

Arthur Ulfeldt
sumber
Ini jawaban terbaik.
Felipe
4
Jawaban yang diterima secara teknis benar, tetapi jawaban ini paling berguna bagi saya. Saya mencoba memetakan suatu fungsi melalui vektor dan kemudian memuntahkan hasilnya ke file, dan bahkan setelah memanggil doall, file tersebut berisi "clojure.lang.LazySeq@address" alih-alih konten urutan. Memanggil vec pada peta nilai kembali memberi saya apa yang perlu saya keluarkan ke file.
Jesse Rosalia
1
@JesseRosalia Senang mengetahui bahwa satu-satunya tanggapan Rich Hickey di semua SO secara teknis benar. ;-)
Phil Cooper
(vec (my-lazy-seq))tidak begitu baik dalam situasi seperti berikut: (vec (json/parse-string "{\"foo\":\"bar\"}")) ;; => [["foo" "bar"]]Sejak cheshirememilih untuk menghasilkan seq-malas dari(json/parse-string)
codeasone
Mitigasi di atas adalah dengan menggunakan eager(json/parse-string-strict)
codeasone
22

Orang kaya ini sepertinya tahu jubahnya dan benar sekali.
Namun, menurut saya cuplikan kode ini, dengan menggunakan contoh Anda, dapat menjadi pelengkap yang berguna untuk pertanyaan ini:

=> (realized? (take 3 (repeatedly rand))) 
false
=> (realized? (doall (take 3 (repeatedly rand)))) 
true

Memang jenisnya tidak berubah tapi realisasinya sudah

Peter
sumber
2
Namun, perlu diperhatikan bahwa Anda tidak perlu memaksa seluruh urutan untuk realized?kembali true. Misalnya(let [r (range) r? (realized? r)] (doall (take 1 r)) [r? (realized? r)]) => [false true]
Alex Coventry
22
Orang Kaya ini: D haha
nimrod
10
@nimrod :) plesetan itu dimaksudkan untuk menjadi "hís clojure".
Peter
10
Bagi mereka yang tidak tahu, "Orang Kaya" yang menemukan Clojure.
erturne
1
@AlexCoventry contoh Anda kembali[true true]
7

Saya tersandung pada posting blog ini tentang doalltidak rekursif. Untuk itu saya menemukan komentar pertama di posting melakukan trik. Sesuatu di sepanjang baris:

(use 'closure.walk)
(postwalk identity nested-lazy-thing)

Saya menemukan ini berguna dalam pengujian unit di mana saya ingin memaksa evaluasi beberapa aplikasi bersarang mapuntuk memaksa kondisi kesalahan.

leeor
sumber
5
(.getClass (into '() (take 3 (repeatedly rand))))
stupa
sumber
3
Ini ide yang buruk. Ini membalikkan urutan input.
amalloy
3
Tentu saja, dalam hal ini membalikkan input tidak ada bedanya, karena hanya 3 angka acak .... :-)
mikera