2012-08-27 18 views
9

En Common Lisp (SBCL 1.0.58) ¿por qué la macro O usa un gensym, pero no AND?En Common Lisp, ¿por qué la macro O usa un gensym, pero no AND?

Por ejemplo,

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> 

Miré a defboot.lisp donde se definen las macros pero no encontró nada relevante en los comentarios.

Respuesta

16

Esto se debe a que los operadores lógicos implementados están destinados a ser short-circuiting y devolver el valor producido por la última forma que evaluaron.

Para lograr esto, and no necesita un gensym porque la última forma que evalúa producirá NIL o será el resultado de la última llamada final a sí mismo.

Por otro lado, or tiene que devolver el primer valor no NIL que evalúa, por lo que no puede confiar en la llamada final. Se necesita un gensym a hacer eso, porque sin uno:

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

1 aparece dos veces en la expansión, y en nuestro caso eso significa que la expresión que produce 1 se evalúa dos veces . And you never want that in your macros.

+0

Sí, ya lo veo. Gracias. – kes

4

Digamos que a es falso, pero b, c y d son verdaderos. Ahora, debido a cortocircuitos tenemos:

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

Como se puede ver, en el caso AND, el valor del argumento más a la izquierda nunca se usa como valor de retorno de la forma (a menos que haya sólo un argumento , en cuyo caso la expansión es diferente). En el caso OR, por otro lado, el valor del argumento de la izquierda es el valor de retorno si es verdadero. Por lo tanto, AND puede descartar el valor después de probarlo por veracidad (y, por lo tanto, no es necesario almacenarlo en una variable temporal), pero OR no puede.

+0

Gracias Matthias, también una excelente respuesta. – kes

Cuestiones relacionadas