Ăn ý và ăn ý với những người có điều kiện


13

Đây là phần tiếp theo về các ý kiến ​​về câu trả lời này . Các bit sau của mã dường như là tương đương:

(and a b)

(when a b)

Tất nhiên andcho phép bạn đặt nhiều điều kiện hơn: (and a b c d)có nghĩa là(when (and a b c) d)

Tôi có xu hướng whenchỉ sử dụng để thể hiện sự phân nhánh. Có sự khác biệt thực tế? Nó là tốt hơn để sử dụng cái này hay cái khác?

Tôi không có nguồn C của Emacs trong tay; andlà hàm C; whenlà một macro mở rộng ra if, mà chính nó là một hàm C.


"Tất nhiên và cho phép" nên là "Tất nhiên` và 'cho phép", nhưng đó chỉ là thay đổi 2 ký tự và không phải là chỉnh sửa được phép. Không có ghi đè.
Harvey

Câu trả lời:


17

TL; DR: when là về các tác dụng phụ, anddành cho các biểu thức boolean thuần túy.

Như bạn đã nhận thấy, andwhenchỉ khác nhau về cú pháp, nhưng về mặt khác thì hoàn toàn tương đương.

Sự khác biệt cú pháp là khá quan trọng, mặc dù: whenbao bọc một ẩn ý prognxung quanh tất cả trừ các hình thức đối số đầu tiên. prognlà một tính năng bắt buộc: Nó đánh giá tất cả trừ hình thức cơ thể cuối cùng chỉ cho các tác dụng phụ của chúng, loại bỏ bất kỳ giá trị nào chúng trả về.

Như vậy, whencũng là một hình thức bắt buộc: Mục đích chính của nó là bọc các hình thức tác dụng phụ, bởi vì chỉ có giá trị của hình thức cuối cùng thực sự quan trọng đối với cơ thể.

andmặt khác là một hàm thuần túy, với mục đích chính là xem xét các giá trị trả về của các mẫu đối số đã cho: Trừ khi bạn bao bọc rõ ràng prognbất kỳ đối số nào của nó, giá trị của mọi dạng đối số đều quan trọng và không có giá trị nào bị bỏ qua .

Do đó, sự khác biệt thực sự giữa andwhenlà phong cách: Bạn sử dụng andcho các biểu thức boolean thuần túy, và whenđể bảo vệ xung quanh các hình thức hiệu ứng phụ.

Do đó, đây là phong cách xấu:

;; `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)))

Và đây là những điều tốt:

(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)))

Tôi biết rằng một số người không đồng ý về điều này, và vui vẻ sử dụng andđể bảo vệ các tác dụng phụ, nhưng tôi nghĩ rằng đây thực sự là phong cách xấu. Chúng tôi có các hình thức khác nhau cho một lý do: Vấn đề cú pháp . Nếu không, tất cả chúng ta chỉ sử dụng if, đây là hình thức có điều kiện duy nhất bạn thực sự cần trong Emacs Lisp về mặt ngữ nghĩa. Tất cả các hình thức boolean và điều kiện khác có thể được viết theo if.


2
IMO (nghĩa là theo phong cách tôi sử dụng), andlà về việc quan tâm đến giá trị trả lại . Nó không nhất thiết không phải là về việc sử dụng tác dụng phụ. Nếu chương trình của tôi quan tâm đến giá trị trả về thì tôi sử dụng and. Nếu không thì tôi dùng when. IOW, tôi when chỉ sử dụng cho các tác dụng phụ, nhưng tôi cũng có thể sử dụng một progntrong các đối số and. Đó là về việc giá trị trả lại có quan trọng hay không, không phải là vấn đề đơn độc .
vẽ

5
andkhông phải là một chức năng trong bất kỳ Lisp nào tôi biết. Trong Emacs Lisp, đây là một hình thức đặc biệt, trong Common Lisp, nó là một macro, đơn giản vì nó được dự kiến ​​sẽ có hành vi ngắn mạch (không thể đạt được bằng các hàm, vì chúng luôn đánh giá các đối số của chúng).
Đánh dấu Karpov

2
@lunaryorn, Vâng, nó không thực sự phù hợp, nhưng đó là sự thật, vì vậy tôi nghĩ rằng viết không đúng andlà một chức năng, khi nó không đúng. Không quan trọng là thực tế có liên quan đến câu hỏi như thế nào, chúng ta nên luôn luôn sử dụng các thuật ngữ chính xác, đó là tất cả.
Đánh dấu Karpov

2
Chà, tôi không nghĩ rằng giá trị của mọi hình thức đối số là quan trọng, phù hợp với những gì diễn giải. Nó có thể được thể hiện tốt hơn bằng cách nói rằng không có hình thức nào được đánh giá chỉ để loại bỏ giá trị của nó.
Harald Hanche-Olsen

3
Một phần nào đó trong Cựu Ước, nhưng: Sự khác biệt không chỉ là phong cách trong Lisps mà không chơi chữ nilcó nghĩa là tất cả "sai", "danh sách trống", "khoảng trống", v.v. whenvoid(tức là "không có nghĩa") trong khi đối với andnó là #f("sai"). Mặc dù đây là N / A cho Elisp, nhưng đó là điều mà một người nói chung Lisp có thể xem xét.
Greg Hendershott

4

Hãy để tôi bắt đầu bằng cách nói điều đó (and a b)(when a b)trong ví dụ của bạn làm điều tương tự: Đầu tiên ađược đánh giá. bđược đánh giá nếu ađúng # .

Nhưng andwhenđược sử dụng cho những thứ khác nhau.

  • Bạn sẽ sử dụng (and a b)để trở thành sự thật # nếu cả hai abđúng # (hoặc không nil); và nilnếu không.

  • Bạn sẽ sử dụng (when a b)hoặc chính xác hơn,

    (when a
       ;; do something like b
       )

    khi bạn muốn "b" mã để thực hiện khi và chỉ khi ađúng # .


Đây là một ví dụ nơi bạn sử dụng whenandcùng nhau:

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

Trên, các chức năng do-cđược gọi là chỉ nếu cả hai abđúng # .


Tài liệu tham khảo cho nghiên cứu

# Tất cả các tham chiếu đến đúng tham chiếu đến Boolean TRUE.


3
andkhông trả về tnếu tất cả các đối số của nó là không, nhưng giá trị của đối số cuối cùng.
Tên người dùng có ý nghĩa

1
Bởi t, tôi có nghĩa là Boolean TRUE hoặc không nil. Cảm ơn, tôi sẽ làm rõ điều đó trong câu trả lời của tôi.
Kaushal Modi

Tôi không nghĩ câu trả lời của bạn đi xa hơn những gì tôi đã nêu trong câu hỏi; Tôi biết cả hai làm gì, và ví dụ cuối cùng bạn đưa ra đã xuất hiện trong câu hỏi của tôi ( (when (and a b) c)). Ngoài ra, phần về cách thức andwhengợi ý rằng đó thực sự là cách chúng được sử dụng nói chung, nhưng cơ sở cho câu hỏi này là thực tế tôi thường thấy chúng được sử dụng khác nhau (ví dụ như câu trả lời tôi liên kết trong câu hỏi của tôi).
Clément

Từ quan điểm xây dựng chức năng thuần túy, khi nào là để đánh giá không kết thúc và là cho các biểu tượng trực tiếp và logic boolean. Lập trình chức năng cần sự phân biệt này; lập trình mệnh lệnh fudge này đi.
Người dùng Emacs

1
Tôi không nghĩ "boolean true" rõ ràng hơn là "true".
YoungFrog
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.