Quiero demostrar mi falta de conocimiento con un ejemplo.
Usando las siguientes dos definiciones de macro,
(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 primera macro sombrea cualquier variable nombrada max
que pueda ocurrir en el cuerpo y la segunda no, lo que se puede mostrar con el siguiente ejemplo:
(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)))))
Hasta donde sé, la evaluación de una llamada macro funciona así:
La macro se evalúa dos veces. Primero se evalúa el cuerpo y devuelve un formulario. Este formulario luego se evalúa nuevamente.
Hasta aquí todo bien.
Pero si supongo que la macro realmente devuelve un fragmento de texto que resulta ser una forma de ceceo, que luego se interpreta, obtengo un conflicto que me impide comprender el ejemplo anterior.
¿Qué parte del texto make-symbol
devuelve la segunda macro que usa , para que no se sombree? En mi opinión, un nombre de símbolo elegido aleatorio extremadamente improbable tendría sentido.
Si uso pp-macroexpand...
ambas macros, devuelvo la misma expansión.
¿Alguien puede ayudarme a salir de esta confusión?
fuente
print-gensym
yprint-circle
quet
usted será capaz de ver la diferencia en las expansiones de macro.#:max
. Qué significa eso ? Estoy muy interesado en más detalles.#:
es simplemente una convención de la impresora para indicar un símbolo uninterned (esto es lo queprint-gensym
se enciende), hay más detalle en el manual:(elisp) Creating Symbols
.Respuestas:
Como se menciona en los comentarios, debe activar esta configuración para ver cómo funciona la macroexpansión con mayor precisión. Tenga en cuenta que solo cambia la forma en que
macroexpand
se muestra, las macros siguen funcionando igual en cualquier caso:Luego, la primera instancia se expande a (incorrecta):
Y el segundo se expande a (correcto):
Para comprender mejor la diferencia, considere evaluar esto:
Como puede ver, el resultado de
(make-symbol "max")
no tiene valor. Esto garantiza la exactitud del primer paso de evaluación en la macro. Con el segundo paso eval,#:max
gana un valor ya que ahora está vinculado como una variable dinámica.fuente
print-circle
contrario, tiene 2#:max
que no estáneq
(considere también anidadosfor
).cl-gensym
si aún no está claro.