2008-09-13 9 views
5

He estado trabajando a través Practical Common Lisp y como un ejercicio decidido escribir una macro para determinar si un número es múltiplo de otro número:Mi primera macro Lisp; ¿está agujereado?

(defmacro multp (value factor)
`(= (rem ,value ,factor) 0))

de modo que: (multp 40 10) se evalúa como verdadera mientras (multp 40 13) no

La pregunta es ¿esta macro leak de alguna manera? También está este "buen" Lisp? ¿Ya hay una función/macro existente que podría haber usado?

Respuesta

11

Siebel ofrece un extenso resumen (para casos simples de todos modos) de las posibles fuentes de fugas, y no hay ninguna aquí. Tanto value como factor se evalúan solo una vez y en orden, y rem no tiene ningún efecto secundario.

Sin embargo, esto no es bueno Lisp, porque no hay ninguna razón para usar una macro en este caso. Una función

(defun multp (value factor) 
    (zerop (rem value factor))) 

es idéntica para todos los propósitos prácticos. (Tenga en cuenta el uso de zerop. Creo que aclara las cosas en este caso, pero en los casos en que necesita resaltar, que el valor que está probando puede ser significativo si es distinto de cero, (= ... 0) podría ser mejor)

+0

Eso es genial gracias. ¿Alguna idea de los requisitos para una macro simple justificable para crear como un ejercicio, entonces? –

2

Su macro se ve bien para mí. No sé qué es una macro con fugas, pero la tuya es bastante sencilla y no requiere ningún gensyms. En cuanto a si esto es "bueno" Lisp, mi regla de oro es usar una macro solo cuando una función no funcionará, y en este caso se puede usar una función en lugar de la macro. Sin embargo, si esta solución funciona para usted, no hay razón para no usarla.

1

Bueno, en principio, un usuario podría hacer esto:

(flet ((= (&rest args) nil)) 
    (multp 40 10)) 

que evaluar a NIL ... excepto que ANSI CL hace que sea ilegal para volver a vincular la mayoría de los símbolos estándar, incluyendo: CL =, por lo que Está en el lado seguro en este caso particular.

En general, por supuesto, debe tener en cuenta tanto la falta de transparencia referencial (captura de identificadores del contexto en el que se expande la macro) como la macro antihigiénica (identificadores con fugas en el código expandido).

0

No, ningún símbolo introducido en el "cierre léxico" de la macro se libera al exterior.

Tenga en cuenta que la fuga no es NECESARIAMENTE una mala cosa, incluso si es casi siempre una fuga accidental. Para un proyecto que trabajé, me encontré con que una macro similar a esta fue útil:

(defmacro ana-and (&rest forms) 
    (loop for form in (reverse forms) 
     for completion = form then `(let ((it ,form)) 
             (when it 
             ,completion)) 
     finally (return completion))) 

Esto permitió que consiguiera "cortocircuito" de las cosas que había que hacer en secuencia, con argumentos heredadas del anterior llama en la secuencia (y una falla señalada al devolver NIL). El contexto específico de este código es para un analizador escrito a mano para un archivo de configuración que tiene una sintaxis improvisada suficiente que escribir un analizador apropiado usando un generador de analizador fue más trabajo que laminar manualmente.

Cuestiones relacionadas