2017-05-15 7 views
0

Je:Pourquoi une macro est-elle évaluée lors de la compilation d'une définition de fonction (Clozure Common Lisp)?

(defmacro assign (name value) 
    (format t "assigning ~A to ~A~%" `,name `,value)) 

(defun opcode-call (&rest args) 
    (mapcar (lambda (arg) 
      (if (stringp arg) 
       (let ((var (gensym))) 
        (assign var arg) 
        var) 
       arg)) 
      args)) 

Quand je compile opcode appel, sorties REPL:

assigning VAR to ARG 
OPCODE-CALL 

Pourquoi assignons en cours d'évaluation au moment de la compilation?

+2

Les macros sont toujours développées avant de compiler, de sorte que le code compilé ne comprend que l'expansion. Si vous ne voulez pas que votre macro imprime la sortie pendant la macroexpansion, vous devez retourner le formulaire '(format ...)' au lieu de l'évaluer (placer une citation avant et enlever les deux que vous avez (ce qui n'est pas le cas quoi que ce soit en ce moment de toute façon)). – jkiiski

Répondre

5

Les macros sont des fonctions. Ils prennent le code via leurs arguments et retournent le nouveau code. Les macros peuvent avoir des effets secondaires.

Votre code imprime quelque chose en tant qu'effet secondaire pendant l'expansion de macro et renvoie NIL (le résultat de l'appel de la fonction FORMAT).

(defmacro assign (name value) 
    (format t "assigning ~A to ~A~%" `,name `,value)) 

Son utilisation:

CL-USER 11 > (multiple-value-list (macroexpand '(assign foo bar))) 
assigning FOO to BAR  ; prints as a side effect 
(NIL T)     ; the macro expansion returns two values NIL and T 

Il n'a pas de sens de citer les arguments. Le code est équivalent à ceci:

(defmacro assign (name value) 
    (format t "assigning ~A to ~A~%" name value)) 

Il retourne encore NIL que l'expansion, ce qui est sans doute pas ce que vous voulez.

Si vous souhaitez que la macro développe un formulaire dans l'appel à format, vous devez renvoyer cet appel sous la forme d'une liste. Ici, nous utilisons quasiquote pour construire une liste à partir d'un modèle, en remplissant deux valeurs: name et value.

(defmacro assign (name value) 
    `(format t "assigning ~A to ~A~%" ,name ,value)) 

Peut-être que vous voulez citer le nom:

(defmacro assign (name value) 
    `(format t "assigning ~A to ~A~%" ',name ,value))