“And” vs “when” untuk conditional

13

Ini adalah tindak lanjut dari komentar pada jawaban ini . Bit kode berikut tampaknya setara:

(and a b)

(when a b)

Tentu saja andmemungkinkan Anda menempatkan lebih banyak kondisi: (and a b c d)berarti(when (and a b c) d)

Saya cenderung menggunakan whenhanya untuk mengekspresikan percabangan. Apakah ada perbedaan nyata? Apakah lebih baik menggunakan yang satu atau yang lain?

Saya tidak memiliki sumber C Emacs 'di tangan; andadalah fungsi C; whenadalah makro yang berkembang if, yang itu sendiri adalah fungsi C.

Sejuk
sumber
"Tentu saja dan memungkinkan" harus "Tentu saja` dan `memungkinkan", tetapi itu hanya 2 karakter yang berubah dan tidak boleh diedit. Tidak ada penggantian.
Harvey

Jawaban:

17

TL; DR: when adalah tentang efek samping, andadalah untuk ekspresi boolean murni.

Seperti yang telah Anda perhatikan, anddan whenhanya berbeda dalam sintaksis, tetapi sebaliknya sepenuhnya sama.

Perbedaan sintaksis cukup penting, meskipun: whenmembungkus implisit di prognsekitar semua kecuali bentuk argumen pertama. prognadalah fitur yang secara inheren penting: Ini mengevaluasi semua kecuali bentuk tubuh terakhir untuk efek sampingnya saja, membuang nilai apa pun yang mereka kembalikan.

Dengan demikian, whenadalah bentuk imperatif juga: Tujuan utamanya adalah untuk membungkus bentuk efek samping, karena hanya nilai bentuk terakhir yang paling penting bagi tubuh.

anddi sisi lain adalah fungsi murni, yang tujuan utamanya adalah untuk melihat nilai kembali dari bentuk argumen yang diberikan: Kecuali jika Anda secara eksplisit membungkus prognargumennya, nilai setiap bentuk argumen adalah penting, dan tidak ada nilai yang pernah diabaikan .

Oleh karena itu, perbedaan nyata antara anddan whengaya: Anda gunakan anduntuk ekspresi boolean murni, dan whenuntuk menjaga di sekitar bentuk efek samping.

Karenanya, ini adalah gaya yang buruk:

;; `when' used for a pure boolean expression
(let ((use-buffer (when (buffer-live-p buffer)
                    (file-exists-p (buffer-file-name buffer)))))
  ...)

;; `and' used as guard around a side-effecting form
(and (buffer-file-name buffer) (write-region nil nil (buffer-file-name buffer)))

Dan ini bagus:

(let ((use-buffer (and (buffer-live-p buffer)
                       (file-exists-p (buffer-file-name buffer)))))
  ...)

(when (buffer-file-name buffer)
 (write-region nil nil (buffer-file-name buffer)))

Saya tahu bahwa beberapa orang tidak setuju tentang hal ini, dan dengan senang hati menggunakannya anduntuk menjaga efek samping, tetapi saya pikir ini adalah gaya yang benar-benar buruk. Kami memiliki berbagai bentuk ini karena suatu alasan: Sintaks penting . Jika tidak, kita semua hanya akan menggunakan if, yang merupakan satu-satunya bentuk kondisional yang Anda butuhkan di Emacs Lisp secara semantik. Semua bentuk boolean dan kondisional lainnya dapat ditulis dalam bentuk if.

lunaryorn
sumber
2
IMO (yaitu, dalam gaya yang saya gunakan), andadalah tentang peduli tentang nilai kembali . Ini belum tentu bukan tentang menggunakan efek samping. Jika program saya peduli dengan nilai pengembalian maka saya gunakan and. Jika tidak maka saya gunakan when. TKI, saya gunakan when hanya untuk efek samping, tapi saya mungkin akan menggunakan prognsalah satu argumen untuk itu and. Ini tentang apakah nilai pengembalian itu penting, bukan tentang apakah itu sendiri yang penting.
Drew
5
andbukan fungsi dalam Lisp yang saya tahu. Dalam Emacs Lisp itu adalah bentuk khusus, dalam Common Lisp itu adalah makro, hanya karena itu diharapkan memiliki perilaku hubung singkat (tidak mungkin untuk dicapai dengan fungsi, karena mereka selalu mengevaluasi argumen mereka).
Mark Karpov
2
@ Lunaryorn, Ya, itu tidak benar-benar relevan, tapi itu benar, jadi saya pikir itu salah untuk menulis itu andadalah fungsi, padahal sebenarnya tidak. Tidak masalah seberapa relevan fakta itu dengan pertanyaan, kita harus selalu menggunakan istilah yang benar, itu saja.
Mark Karpov
2
Yah, saya tidak berpikir "nilai dari setiap bentuk argumen itu penting" konsisten dengan apa interpretasi itu. Bisa lebih baik diungkapkan dengan mengatakan bahwa tidak ada bentuk yang dievaluasi hanya untuk memiliki nilainya dibuang.
Harald Hanche-Olsen
3
Agaknya, tetapi: Perbedaannya lebih dari sekadar gaya dalam Lisps yang tidak nilberarti semua "false", "the blank list", "void", dll. Misalnya dalam Skema dan Raket, hasil tidak jujur ​​dari whenadalah void(yaitu "tidak ada artinya") sedangkan untuk anditu adalah #f("salah"). Meskipun ini N / A untuk Elisp, itu sesuatu yang mungkin dipertimbangkan oleh generalis Lisp.
Greg Hendershott
4

Biarkan saya memulai dengan mengatakan itu (and a b)dan (when a b)dalam contoh Anda melakukan hal yang sama: Pertama adievaluasi. bdievaluasi jika aini benar # .

Tetapi and dan whendigunakan untuk hal-hal yang berbeda.

  • Anda akan menggunakan (and a b)untuk kembali benar # jika KEDUA adan byang benar # (atau non-nil); dan nilsebaliknya.

  • Anda akan menggunakan (when a b)atau lebih tepatnya,

    (when a
       ;; do something like b
       )

    bila Anda ingin "b" kode untuk mengeksekusi jika dan hanya jika aadalah benar # .


Berikut adalah contoh tempat Anda menggunakan whendan andbersama - sama:

(when (and a b)
   (do-c))

Di atas, fungsi do-cdisebut hanya jika KEDUA adan byang benar # .


Referensi untuk belajar

# Semua referensi ke true merujuk ke Boolean TRUE.

Kaushal Modi
sumber
3
andtidak kembali tjika semua argumennya bukan nol, tetapi nilai argumen terakhir.
Nama pengguna yang berarti
1
Oleh t, saya berarti Boolean TRUE atau non-nihil. Terima kasih, saya akan menjelaskannya dalam jawaban saya.
Kaushal Modi
Saya tidak berpikir jawaban Anda lebih jauh dari apa yang telah saya nyatakan dalam pertanyaan; Saya tahu apa yang keduanya lakukan, dan contoh terakhir yang Anda berikan sudah muncul di pertanyaan saya ( (when (and a b) c)). Selain itu, bagian tentang bagaimana anddan whenmenyarankan bahwa itulah sebenarnya cara mereka digunakan secara umum, tetapi dasar dari pertanyaan ini adalah kenyataan bahwa saya sering melihat mereka digunakan secara berbeda (lihat misalnya jawaban yang saya tautkan dalam pertanyaan saya).
Clément
Dari sudut pandang konstruk yang berfungsi murni, kapan evaluasi non-terminasi dan dan untuk simbol langsung dan logika boolean. Pemrograman fungsional membutuhkan perbedaan ini; pemrograman imperatif fudge ini.
Pengguna Emacs
1
Saya tidak berpikir "boolean true" lebih jelas dari sekedar "benar".
YoungFrog