Quero demonstrar minha falta de conhecimento com um exemplo.
Usando as duas definições de macro a seguir,
(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))))))
a primeira macro oculta todas as variáveis nomeadas max
que podem ocorrer no corpo e a segunda não, o que pode ser mostrado com o seguinte exemplo:
(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)))))
Tanto quanto eu aprendi, a avaliação de uma chamada macro funciona assim:
A macro é avaliada duas vezes. Primeiro, o corpo é avaliado e retorna um formulário. Este formulário é avaliado novamente.
Por enquanto, tudo bem.
Mas se eu presumir que a macro realmente retorna um pedaço de texto que, por acaso, é uma forma lisp, que depois é interpretada, eu recebo um conflito que me torna incapaz de entender o exemplo acima.
Que parte do texto make-symbol
retorna a segunda macro que usa , para que não ocorra sombra? No meu entendimento, um nome de símbolo escolhido aleatoriamente extremamente improvável faria sentido.
Se eu usar as pp-macroexpand...
duas macros, retorne a mesma expansão.
Alguém é capaz de me ajudar a sair dessa confusão?
fonte
print-gensym
eprint-circle
parat
você, poderá ver a diferença nas expansões de macro.#:max
. O que isso significa ? Estou muito interessado em mais detalhes.#:
é apenas uma convenção da impressora para indicar um símbolo uninterned (isto é o queprint-gensym
se acende), não há mais detalhes no manual:(elisp) Creating Symbols
.Respostas:
Conforme mencionado nos comentários, é necessário ativar essa configuração para ver como a macroexpansão funciona com mais precisão. Observe que isso muda apenas como
macroexpand
é exibido, as macros ainda funcionam da mesma maneira em ambos os casos:Em seguida, a primeira instância se expande para (incorreta):
E o segundo se expande para (correto):
Para entender melhor a diferença, considere avaliar isso:
Como você pode ver, o resultado de
(make-symbol "max")
não tem valor. Isso garante a correção da primeira passagem de avaliação na macro. Com o segundo passe de avaliação,#:max
ganha um valor, pois agora está vinculado como uma variável dinâmica.fonte
print-circle
outros 2#:max
que não sãoeq
(considere também aninhadosfor
).cl-gensym
se ainda não está claro.