2012-08-27 17 views
9

W Common Lisp (SBCL 1.0.58) dlaczego makro LUB używa gensym, ale nie AND?W Common Lisp Dlaczego makro LUB używa Gensym, ale nie ORAZ?

Na przykład

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> 

Spojrzałem na defboot.lisp gdzie makra są zdefiniowane, ale nic nie znalazłem odpowiedniego w komentarzach.

Odpowiedz

16

Dzieje się tak, ponieważ zaimplementowane operatory logiczne mają być short-circuiting i zwracać wartość wytworzoną przez ostatni formularz, który ocenili.

Aby to osiągnąć, and nie potrzebuje gensym, ponieważ ostatnia forma, którą ocenia, może wytworzyć NIL lub być wynikiem ostatniego ogona do siebie.

Z drugiej strony, or musi zwrócić pierwszą ocenioną wartość inną niż NIL, aby nie mogła polegać na wywołaniu ogonowym. Potrzebuje gensym to zrobić, ponieważ bez niego:

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

1 pojawia się dwukrotnie w ekspansji, aw naszym przypadku oznacza to, że wyrażenie, które produkuje 1 jest oceniany dwukrotnie. And you never want that in your macros.

+0

Tak, teraz to widzę. Dziękuję Ci. – kes

4

Powiedzmy a jest fałszywa, ale b, c, a d są prawdziwe. Teraz, z powodu zwarcia mamy:

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

Jak widać, w przypadku AND wartość skrajnego lewego argumentu nigdy nie jest używana jako wartość zwracana postaci (chyba, że ​​jest tylko jeden argument , w którym to przypadku ekspansja jest inna). Z kolei w przypadku OR wartość skrajnego lewego argumentu jest wartością zwracaną, jeśli jest prawdziwa. Dlatego AND może odrzucić wartość po przetestowaniu jej pod kątem prawdziwości (a zatem nie musi przechowywać jej w zmiennej tymczasowej), ale nie może.

+0

Dziękuję Matthias, również doskonałą odpowiedź. – kes