Translate

sábado, 11 de junio de 2016

Macros

Se utilizan para generar código en lugar de realizar necesariamente algo.

Antes de comenzar con la macro voy a explicar algunas consideraciones sobre la sintaxis.

Una comilla hacia la izquierda (`) antes de cualquier expresión detiene la evaluación de la lista que le sigue del mismo modo que la comilla simple (')

> `(1 2 3)
(1 2 3)
> '(1 2 3)
(1 2 3)

Sin embargo, en la expresión que tiene la comilla hacia la izquierda, cualquier sublista precedida por una coma (,) será evaluada. Vea los efectos de la coma en la siguiente expresión:

> `(1 2 (+ 1 2))  
(1 2 (+ 1 2))

> `(1 2 ,(+ 1 2))  
(1 2 3)

Existe una variante de la coma (,) que es la coma con arroba (,@). Lo que hace ,@ es devolver los valores que se encuentran dentro de la lista que se devuelve, es decir la misma lista pero sin los parentesis. De esta manera se pueden "agregar" los valores devueltos a una lista que la contiene. Puedes ver la diferencia entre , y ,@ en las siguientes expresiones:

> `(and ,(list 1 2 3)) 
(AND (1 2 3))
> `(and ,@(list 1 2 3)) 
(AND 1 2 3)

También puedes usar ,@ para agregar valores en el medio de una lista:

> `(and ,@(list 1 2 3) 4) 
(AND 1 2 3 4)

Bien ;-) comencemos con la macro. Para crear una macro utilizamos defmacro.

(defmacro si-ocurre (condicion &rest cuerpo)

Si se verifica que "condicion" es verdad, la macro ejecuta las sentencias de "cuerpo".
Falta colocar que va a hacer la macro.

(defmacro si-ocurre (condicion &rest cuerpo)
    `(if ,condicion (progn ,@cuerpo) (format t "No puede conducir ~%")))

La coma (,) antes de "condicion" significa que la lista que se pasa como condicion será evaluada. La ,@ antes de "cuerpo" indica que se agregan las sentencias a la lista que la contiene, es decir, la lista con (progn s1 s2 ... sn), pues el argumento que se pasa a cuerpo es una lista de listas (s1 s2 ... sn)

Recordemos que &rest permite pasar un numero arbitrario de argumentos a la función o macro, y estos quedan dentro de una lista que los contiene. Por lo tanto "cuerpo" contendrá una lista de listas. 

Con esto se genera una nueva macro que recibe condiciones y ejecuta un cuerpo de sentencias. Bien, el poder de las macros permite que se escriba muy poco código para realizar un programa. Ademas hace mas claro el programa, evitando el uso de progn.
Probemos nuestra macro:

> (setf *edad* 16)
> (si-ocurre (>= *edad* 16) 
     (print "Ya tienes 16 años o mas")
     (print "Estas listo para conducir")
     (terpri))

"Ya tienes 16 años o mas")
"Estas listo para conducir"

Otra vez...

> (setf *edad* 15)
> (si-ocurre (>= *edad* 16) 
     (print "Ya tienes 16 años")
     (print "Estas listo para conducir")
     (terpri))

"No puede conducir"

Ok! .-) Saludos

No hay comentarios:

Publicar un comentario