Remarque:
Ne pas utiliser de macro si on peut s'en passer.
En particulier cette remarque s'applique ici car un (defun square (x)
....)
ferait très bien l'affaire mais cet exemple est choisi pour sa
simplicité.
Exemple 1
On crée une macro square qui calcule le carré de son argument.
* (defmacro square (x) (* x x))
SQUARE
* (square 4)
16
* (defvar az 4)
AZ
* (square az)
debugger invoked on a SIMPLE-TYPE-ERROR in thread
#
Argument X is not a NUMBER: AZ
Le problème est que la valeur de az n'est pas transmise
à la macro.
Une solution est d'utiliser la backquote ` (1)
* (defmacro square (x) `(* ,x ,x))
SQUARE
*(square az)
16
Cette fois cela fonctionne avec les variables mais il y a enccore un problème:
* (setf az 4)
* (square (incf az))
30 (valeur attendue 25)
Utilisons la fonction macroexpand pour voir ce qu'il se passe.
* (macroexpand '(square (incf az)))
(* (INCF AZ) (INCF AZ))
T
La variable az est incrémentée deux fois, donc on calcule 5*6.
Solution:
(defmacro square (x)
`(let ((temp ,x))
(* temp temp)))
* (setf az 4)
* (square (incf az))
25
La virgule, à l'intérieur de la backquote, permet l'évaluation du symbole qui la suit.
(defvar e "macro")
`(a z ,e r t y) => (a z "macro" r t y)
`(a z ,(+ 2 3) r t y) => (a z 5 r t y)