Mengapa lebih memilih seq daripada non-kosong sebagai predikat?

Dokumen untuk empty? mengatakan "Silakan gunakan idiom (seq x) daripada (bukan (kosong? x))". MisterMetaphor menunjukkan bahwa penggunaan seq sebagai predikat bisa masuk akal bila digunakan di if-let:

(if-let [s (seq might-be-empty)]
   (fn-for-non-empty-seq s)
   (fn-for-empty-seq))

Namun, haruskah saya menggunakan seq untuk menguji ketidakkosongan secara umum? seq dapat mengubah argumennya ke bentuk lain. Misalnya:

user=> (class (lazy-seq '(1 2 3)))
clojure.lang.LazySeq
user=> (class (seq (lazy-seq '(1 2 3))))
clojure.lang.PersistentList
user=> (class (map inc [1 2 3]))
clojure.lang.LazySeq
user=> (class (seq (map inc [1 2 3])))
clojure.lang.ChunkedCons

Sepertinya membuang-buang siklus jika hanya ingin menguji ketidakkosongan, dan tidak memerlukan pengikatan baru, atau jika saya tidak memerlukan konversi sebelum pengikatan. Bukankah not-empty merupakan pilihan yang lebih baik dalam kasus seperti itu? Ia mengembalikan nil jika argumennya kosong, dan argumennya tidak berubah jika tidak kosong.

(if (not-empty [])
  "more to do"
  "all done")

person Mars    schedule 06.02.2014    source sumber


Jawaban (1)


Pertama, periksa definisi empty?:

(defn empty?
  "Returns true if coll has no items - same as (not (seq coll)).
  Please use the idiom (seq x) rather than (not (empty? x))"
  {:added "1.0"
  :static true}
  [coll] (not (seq coll)))

Jadi empty? adalah (not (seq coll)). Itu sebabnya tidak disarankan untuk melengkapi empty?, karena Anda melakukan negasi ganda pada seq.

Sekarang lihat not-empty

(defn not-empty
  "If coll is empty, returns nil, else coll"
  {:added "1.0"
   :static true}
  [coll] (when (seq coll) coll))

Kejutannya, ia juga menggunakan seq sebagai ujian ketidakkosongan. not-empty ini berguna jika jenisnya penting -- kinerja nth pada vektor, perilaku conj, dll. -- karena ia mengembalikan kolom yang tidak kosong sebagaimana adanya. Digunakan hanya sebagai predikat, itu hanya akan membungkus seq.

Namun jangan khawatir tentang seq yang bersifat berat. Itu tidak lebih dari mengembalikan sebuah iterator. Itu tidak benar-benar mengubah seluruh struktur data.

person A. Webb    schedule 06.02.2014
comment
Terima kasih. Menarik, dan mengejutkan, bahwa biaya tambahan apa pun (mengembalikan iterator) harus dibayar untuk operasi yang sering digunakan. Atau lebih tepatnya, sebenarnya hal ini tidak memerlukan biaya sama sekali, dan sekali lagi, ini sangat menarik. - person Mars; 06.02.2014
comment
Saya berharap kompiler JIT tidak memiliki masalah dengan mengoptimalkan negasi ganda. - person remcycles; 19.06.2018
comment
@ remicles2 Saya tidak dapat membayangkan pengoptimalan dalam bahasa yang diketik secara dinamis dengan fragmen yang lambat menjadi begitu menarik. Apakah ada makalah yang mengatakan berapa banyak pekerjaan yang mampu dilakukan JIT sebelum mencapai rintangan besar? - person David Tonhofer; 18.05.2019