2012-08-27 6 views
9

In Common Lisp (SBCL 1.0.58) warum verwendet das Makro OR ein Gensym, aber nicht UND?In Common Lisp warum verwendet das Makro ODER ein Gensym, aber nicht UND?

Zum Beispiel

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> 

ich defboot.lisp sah, wo die Makros definiert sind, aber nichts relevant in den Kommentaren gefunden.

Antwort

16

Das ist, weil die implementierten logischen Operatoren short-circuiting sein sollen und den Wert zurückgeben sollen, der von der letzten Form erzeugt wurde, die sie auswerteten.

Um dies zu erreichen, benötigt and keine gensym, weil die letzte Form, die es auswertet, entweder NIL produziert oder das Ergebnis des letzten Tail Calls selbst ist.

Auf der anderen Seite muss or den ersten nicht NIL Wert zurückgeben, der ausgewertet wird, so dass es sich nicht auf den Tail Call verlassen kann. Es braucht ein gensym, das zu tun, denn ohne ein:

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

1 erscheint zweimal in der Expansion, und in unserem Fall bedeutet der Ausdruck, dass 1 erzeugt wird zweimal ausgewertet. And you never want that in your macros.

+0

Ja, das sehe ich jetzt. Vielen Dank. – kes

4

Nehmen wir an, a ist falsch, aber b, c und d sind wahr. Nun, da der Kurzschluss haben wir:

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

Wie Sie sehen können, in der AND Fall wird der Wert des äußersten linken Argument nie als Rückgabewert der Form verwendet wird (es sei denn, es gibt nur ein Argument In diesem Fall ist die Erweiterung anders). Im Fall OR hingegen ist der Wert des Arguments ganz links der Rückgabewert, wenn es wahr ist. Daher kann AND den Wert verwerfen, nachdem er auf Wahrheit geprüft wurde (und muss daher nicht in einer temporären Variablen gespeichert werden), aber OR kann nicht.

+0

Danke Matthias, auch eine ausgezeichnete Antwort. – kes