Ich möchte meinen Mangel an Wissen anhand eines Beispiels demonstrieren.
Verwenden Sie die folgenden zwei Makrodefinitionen:
(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))))))
Das erste Makro schattiert alle benannten Variablen, max
die im Körper auftreten können, und das zweite nicht, was anhand des folgenden Beispiels gezeigt werden kann:
(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)))))
Soweit ich erfahren habe, funktioniert die Auswertung eines Makroaufrufs folgendermaßen:
Das Makro wird zweimal ausgewertet. Zuerst wird der Körper ausgewertet und gibt ein Formular zurück. Dieses Formular wird dann erneut ausgewertet.
So weit, ist es gut.
Wenn ich jedoch davon ausgehe, dass das Makro wirklich einen Textblock zurückgibt, der zufällig eine Lisp-Form ist und dann interpretiert wird, entsteht ein Konflikt, der mich dazu bringt, das obige Beispiel nicht zu verstehen.
Welchen Textblock gibt das zweite Makro, das make-symbol
return verwendet, so dass keine Schattenbildung auftritt? Nach meinem Verständnis wäre ein extrem unwahrscheinlicher, zufällig gewählter Symbolname sinnvoll.
Wenn ich pp-macroexpand...
beide Makros verwende, wird dieselbe Erweiterung zurückgegeben.
Kann mir jemand aus dieser Verwirrung helfen?
quelle
print-gensym
undprint-circle
auf setzen , könnent
Sie den Unterschied in den Makroerweiterungen sehen.#:max
. Was bedeutet das ? Ich bin sehr an weiteren Details interessiert.#:
ist nur eine Konvention des Druckers ein uninterned Symbol , um anzuzeigen , (das ist , wasprint-gensym
antörnt), gibt es mehr ausführlich im Handbuch:(elisp) Creating Symbols
.Antworten:
Wie in den Kommentaren erwähnt, müssen Sie diese Einstellung aktivieren, um zu sehen, wie die Makroerweiterung genauer funktioniert. Beachten Sie, dass sich nur die
macroexpand
Anzeige ändert . Die Makros funktionieren in beiden Fällen immer noch gleich:Dann wird die erste Instanz auf (falsch) erweitert:
Und der zweite erweitert sich zu (richtig):
Um den Unterschied besser zu verstehen, sollten Sie Folgendes bewerten:
Wie Sie sehen können, hat das Ergebnis von
(make-symbol "max")
keinen Wert. Dies stellt die Richtigkeit des ersten Auswertungsdurchlaufs des Makros sicher. Erhält mit dem zweiten Auswertungsdurchgang#:max
einen Wert, da er jetzt als dynamische Variable gebunden ist.quelle
print-circle
sonst 2 haben#:max
, die nicht sindeq
(betrachten Sie auch verschachteltfor
).cl-gensym
ob es noch nicht klar ist.