Je veux démontrer mon manque de connaissances avec un exemple.
En utilisant les deux définitions de macro suivantes,
(defmacro for (var from init to final do &rest body)
"Execute a simple for loop: (for i from 1 to 10 do (print i))."
(let ((tempvar 'max))
`(let ((,var ,init)
(,tempvar ,final))
(while (<= ,var ,tempvar)
,@body
(setq ,var (1+ ,var))))))
(defmacro for (var from init to final do &rest body)
"Execute a simple for loop: (for i from 1 to 10 do (print i))."
(let ((tempvar (make-symbol "max")))
`(let ((,var ,init)
(,tempvar ,final))
(while (<= ,var ,tempvar)
,@body
(setq ,var (1+ ,var))))))
la première macro masque toutes les variables nommées max
qui peuvent se produire dans le corps et la seconde non, ce qui peut être montré avec l'exemple suivant:
(let ((max 0)) ;; this variable is shadowed if the first macro defintion is used
(for i from 1 to 3 do
(setq square (* i i))
(if (> square max)
(princ (format "\n%d %d" i square)))))
Pour autant que j'ai appris l'évaluation d'un macro appel fonctionne comme ceci:
La macro est évaluée deux fois. Le corps est d'abord évalué et retourne un formulaire. Ce formulaire est ensuite évalué à nouveau.
Jusqu'ici tout va bien.
Mais si je suppose que la macro renvoie vraiment un morceau de texte qui se trouve être une forme lisp, qui est ensuite interprétée, j'obtiens un conflit qui me rend incapable de comprendre l'exemple ci-dessus.
Quel morceau de texte la deuxième macro qui utilise make-symbol
retourne-t-elle, afin qu'il n'y ait pas d'observation À mon avis, un nom de symbole choisi au hasard extrêmement improbable aurait du sens.
Si j'utilise les pp-macroexpand...
deux macros, renvoyez la même extension.
Est-ce que quelqu'un peut m'aider à sortir de cette confusion?
la source
print-gensym
etprint-circle
pourt
vous pourrez voir la différence dans les extensions de macro.#:max
. Qu'est-ce que ça veut dire ? Je suis très intéressé par plus de détails.#:
est juste une convention de l'imprimante pour indiquer un symbole uninterned (ce qui est ce quiprint-gensym
se met en marche), il est plus en détail dans le manuel:(elisp) Creating Symbols
.Réponses:
Comme mentionné dans les commentaires, vous devez activer ce paramètre pour voir comment la macro-expansion fonctionne plus précisément. Notez que cela ne change que la façon dont
macroexpand
est affiché, les macros fonctionnent toujours de la même façon dans les deux cas:Ensuite, la première instance se développe en (incorrect):
Et le second se développe pour (corriger):
Pour mieux comprendre la différence, envisagez d'évaluer ceci:
Comme vous pouvez le voir, le résultat de
(make-symbol "max")
n'a aucune valeur. Cela garantit l'exactitude de la première passe d'évaluation sur la macro. Avec la deuxième passe d'#:max
évaluation , gagne une valeur car elle est maintenant liée en tant que variable dynamique.la source
print-circle
sinon vous en avez 2#:max
qui ne le sont paseq
(pensez aussi à imbriquerfor
).cl-gensym
si ce n'est toujours pas clair.