Ich versuche, ein Makro zu schreiben, das eine Liste von Variablen und eine Stelle des Codes nimmt und stellt sicher, dass Variablen auf ihre ursprünglichen Werte zurück, nachdem der Code ausgeführt wird (Übung 10.6 in Paul Graham's ANSI Common Lisp).Liste gensym Symbol nicht im Inneren Makro bewertet
Allerdings bin ich mir nicht klar, warum meine gensym
auswertet, wie ich es an einem Ort erwarten, aber nicht ein anderes ähnliches (Note. Ich weiß, dass es eine bessere Lösung für die Übung, die ich will nur herausfinden, warum der Unterschied in der Bewertung).
Hier ist die erste Definition, wo die lst
gensym auf eine Liste innerhalb der die mapcar
weitergegeben lambda
bewertet:
(defmacro exec-reset-vars-1 (vars body)
(let ((lst (gensym)))
`(let ((,lst ,(reduce #'(lambda (acc var) `(cons ,(symbol-value var) ,acc))
vars
:initial-value nil)))
,@body
,@(mapcar #'(lambda (var) `(setf ,var (car ,lst)))
vars))))
Aber während es genau funktioniert, wie ich es erwarten, es ist nicht die richtige Lösung für die Übung, weil ich immer das erste Element von lst
greifen, wenn ich versuche, Werte zurückzusetzen. Ich möchte wirklich über 2 Listen abbilden. So, jetzt schreibe ich:
(defmacro exec-reset-vars-2 (vars body)
(let ((lst (gensym)))
`(let ((,lst ,(reduce #'(lambda (acc var) `(cons ,(symbol-value var) ,acc))
vars
:initial-value nil)))
,@body
,@(mapcar #'(lambda (var val) `(setf ,var ,val))
vars
lst))))
Aber jetzt bekomme ich einen Fehler, der sagt #:G3984
keine Liste ist. Wenn ich es durch (symbol-value lst)
ersetze, erhalte ich einen Fehler, der besagt, dass Variable keinen Wert hat. Aber warum nicht? Warum hat es einen Wert innerhalb der setf
in lambda
, aber nicht als ein Argument an mapcar
übergeben?
Vielen Dank für Ihre Antwort. Um sicherzugehen, dass ich richtig verstehe, hat 'lst' in beiden Fällen den gleichen Wert während der Makroexpansion - ein Symbol. Der Unterschied besteht darin, dass im ersten Fall "(car, lst)" expandiert wird und dann seine expandierte Form während der Laufzeit ausgewertet wird, wobei "lst" eine Liste ist; während in der zweiten, als das Argument zu "mapcar", es während der Makroexpansion ausgewertet wird. Ist das richtig? –
@UnixOne: Nein. Zur Laufzeit gibt es keine 'lst', sondern die Variable mit einem Namen, der zum Makroexpansionszeitpunkt den Wert von' lst' hatte. –