macros - defun - lisp syntax
Mi primera macro Lisp; ¿está agujereado? (4)
Bueno, en principio, un usuario podría hacer esto:
(flet ((= (&rest args) nil))
(multp 40 10))
que evaluaría a NIL ... excepto que ANSI CL hace que sea ilegal volver a enlazar la mayoría de los símbolos estándar, incluido 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 no higiene (los identificadores de fuga para el código expandido).
He estado trabajando con Practical Common Lisp y como ejercicio decidí escribir una macro para determinar si un número es un múltiplo de otro número:
(defmacro multp (value factor)
`(= (rem ,value ,factor) 0))
de modo que: (multp 40 10)
evalúa como verdadero mientras que (multp 40 13)
no
La pregunta es, ¿esta macro se escapa de alguna manera? También está este "buen" Lisp? ¿Ya hay una función / macro existente que podría haber usado?
No, ningún símbolo introducido en el "cierre léxico" de la macro se lanza al exterior.
Tenga en cuenta que la fuga no es NECESARIAMENTE una cosa mala, incluso si es casi siempre una filtración accidental. Para un proyecto en el que trabajé, encontré que una macro similar a esta era ú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 me permitió hacer un "cortocircuito" de las cosas que deben hacerse en secuencia, con los argumentos transferidos de las llamadas anteriores en la secuencia (y una falla señalada al devolver el 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.
Siebel ofrece un extenso resumen (para casos simples de todos modos) de posibles fuentes de fugas, y no hay ninguno de esos aquí. Tanto el value
como el factor
se evalúan solo una vez y en orden, y rem
no tiene ningún efecto secundario.
Aunque 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éntico 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 seguir siendo significativo si es distinto de cero, (= ... 0)
podría ser mejor)
Tu 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.