2012-08-27 76 views
9

In Common Lisp(SBCL 1.0.58)爲什麼宏OR使用gensym,但不是AND?在Common Lisp中,爲什麼宏使用gensym,但不是AND?

例如,

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> 

我看着在宏定義defboot.lisp卻一無所獲的評論相關。

回答

16

這是因爲實施的邏輯運算符的目的是爲short-circuiting並返回他們評估的最後一種形式產生的值。

爲了達到這個目的,and不需要gensym,因爲它所評估的最後一種格式將產生NIL或者是自身最終尾部調用的結果。

另一方面,or必須返回它評估的第一個非NIL值,因此它不能依賴尾部調用。它需要一個gensym做到這一點,因爲在沒有一個:

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

1在膨脹中出現兩次,並在我們的情況下,這意味着,產生1表達式求值兩次And you never want that in your macros

+0

是的,我現在明白了。謝謝。 – kes

4

假設a爲假,但b,cd爲真。現在,因爲短路的有:

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

正如你所看到的,在AND情況下,最左邊的參數的值永遠不會用作形式的返回值(除非只有一個參數在這種情況下擴展是不同的)。另一方面,在OR的情況下,最左邊的參數的值是返回值,如果它是真的。因此,AND可以在測試真實性後丟棄該值(因此不需要將其存儲在臨時變量中),但OR不能。

+0

謝謝馬提亞斯,也是一個很好的答案。 – kes