2012-08-27 25 views
9

Trong Lisp thông thường (SBCL 1.0.58) tại sao macro HOẶC sử dụng gensym, nhưng không phải AND?Trong Lisp thường gặp tại sao macro HOẶC sử dụng một gensym, nhưng không phải AND?

Ví dụ,

CL-USER> (macroexpand '(and 1 2 3 4 5)) 
    (IF 1 
     (AND 2 3 4 5) 
     NIL) 
    T 
    CL-USER> (macroexpand '(or 1 2 3 4 5)) 
    (LET ((#:G967 1)) 
     (IF #:G967 
      #:G967 
      (OR 2 3 4 5))) 
    T 
    CL-USER> 

Tôi nhìn defboot.lisp nơi các macro được định nghĩa nhưng thấy không có gì có liên quan trong các ý kiến.

Trả lời

16

Đó là bởi vì các toán tử logic được triển khai dự định là short-circuiting và trả về giá trị được tạo ra bởi biểu mẫu cuối cùng mà chúng đã đánh giá.

Để đạt được điều này, and không cần gensym vì biểu mẫu cuối cùng được đánh giá sẽ sản xuất NIL hoặc là kết quả của cuộc gọi đuôi cuối cùng.

Mặt khác, or phải trả về giá trị đầu tiên không phải là NIL mà nó đánh giá, vì vậy nó không thể dựa vào cuộc gọi đuôi. Nó cần một gensym để làm điều đó, bởi vì không có một:

(IF 1 
    1 
    (OR 2 3 4 5)) 

1 xuất hiện hai lần trong việc mở rộng, và trong trường hợp của chúng tôi có nghĩa là sự biểu hiện sản xuất 1 được đánh giá hai lần. And you never want that in your macros.

+0

Có, tôi thấy điều đó ngay bây giờ. Cảm ơn bạn. – kes

4

Giả sử a là sai, nhưng b, cd là đúng. Bây giờ, vì ngắn mạch ta có:

(or a b c d) => b 
(and a b c d) => nil 
(or b c d) => b 
(and b c d) => d 

Như bạn có thể thấy, trong trường hợp AND, giá trị của các đối số tận cùng bên trái không bao giờ được sử dụng như là giá trị trả về có dạng (trừ trường hợp chỉ có một lập luận , trong trường hợp đó việc mở rộng khác nhau). Trong trường hợp OR, mặt khác, giá trị của đối số ngoài cùng bên trái là giá trị trả về nếu nó là đúng. Do đó, AND có thể hủy bỏ giá trị sau khi thử nghiệm tính trung thực (và do đó không cần lưu trữ nó trong một biến tạm thời), nhưng OR không thể.

+0

Cảm ơn bạn Matthias, cũng là một câu trả lời tuyệt vời. – kes

Các vấn đề liên quan