wird zu
erweitert %Vor%Was erweitert sich zu dem folgenden:
%Vor%? Gibt es dafür ein Standardmakro?
Wie andere Antworten und Kommentare gezeigt haben, gibt es dafür kein Standardmakro, und Sie können Ihr eigenes schreiben. Meiner Meinung nach ist dies ein guter Fall für define-modify-macro
und ich werde das zuerst beschreiben. Sie können ein solches Makro auch manuell schreiben, indem Sie get-setf-expansion
verwenden, und ich werde ein Beispiel dafür zeigen. auch.
define-modify-macro
Eines der Beispiele auf der HyperSpec-Seite für define-modify-macro
ist appendf
:
Beschreibung:
define-modify-macro definiert einen Makro namens name, um einen Ort zu lesen und zu schreiben.
Die Argumente für das neue Makro sind eine Stelle, gefolgt von den Argumenten, die in der Lambda-Liste angegeben sind. Makros, die mit define-modify-macro definiert wurden, übergeben den Umgebungsparameter korrekt an get-setf-expansion.
Wenn das Makro aufgerufen wird, wird die Funktion auf die alten Inhalte der Stelle und die Lambda-Listen-Argumente angewendet, um den neuen Wert zu erhalten, und die Stelle wird aktualisiert, um das Ergebnis zu enthalten.
Beispiele
%Vor%
Das appendf
im Beispiel ist umgekehrt zu dem, wonach Sie suchen, da die zusätzlichen Argumente als das Ende des place
-Arguments angehängt werden. Wir können jedoch die funktionale Version des gewünschten Verhaltens schreiben (es ist nur append
mit ausgetauschter Argumentreihenfolge) und dann define-modify-macro
:
Wenn Sie swapped-append
nicht als Funktion definieren möchten, können Sie lambda
-Ausdruck auf define-modify-macro
:
Die Antwort lautet also, dass (swapped-appendf list list2)
vom Konzept her auf (setq list (append list2 list))
erweitert wird. Es ist immer noch so, dass die Argumente für swapped-appendf
in der falschen Reihenfolge zu sein scheinen. Wenn wir push
mit define-modify-macro
und cons
definiert hätten, wären die Argumente in einer anderen Reihenfolge als die Standard push
:
define-modify-macro
ist ein nützliches Werkzeug, das ich kennen sollte, und ich fand es nützlich, wenn funktionale (dh nicht seiteneffektive) Versionen von Funktionen leicht zu schreiben sind und eine modifizierende Version auch für eine API gewünscht wird.
get-setf-expansion
new-push
sind list
und item
, während die Argumente von push
item
und list
sind. Ich glaube nicht, dass die Reihenfolge der Argumente in swapped-appendf
genauso wichtig ist, da es kein Standard-Idiom ist. Es ist jedoch möglich, die andere Reihenfolge zu erreichen, indem Sie ein Makro prependf
schreiben, dessen Implementierung get-setf-expansion
Die Verwendung von get-setf-expansion
bedeutet, dass dieses Makro auch an komplizierteren Orten funktioniert:
Für Bildungszwecke ist es interessant, die relevanten Makroexpansionen zu sehen und zu sehen, wie sie mehrere Auswertungen der Formulare vermeiden und welche writer-form
s verwendet werden, um den Wert tatsächlich festzulegen. In get-setf-expansion
ist eine Menge Funktionalität gebündelt, und einige davon sind implementierungsspezifisch:
Um die Dinge ein wenig zu klären, über Vatine Antwort:
Mit der ersten Frage haben wir
%Vor%Das heißt, list2 wird der Liste vorangestellt, aber list2 wird nicht selbst geändert. Der Grund ist einfach, dass append seine Argumente nicht direkt ändert.
Jetzt mit
%Vor%Versuchen Sie es zuerst
%Vor%Zweiter Versuch, Wechsel der Argumente
%Vor%Wie auch immer, eine der Listen wird an die andere angehängt, einfach weil nconc oder (rplacd (last ...) ...) oder hier, direkt (setf (cdr (last ...)) ...), kann nur anhängen, nicht vorgeben . Und wir können nicht einfach behaupten, dass der erste Versuch die richtige Antwort gibt (4 5 6 1 2 3), weil list nicht geändert wurde, während list2 war, was ist absolut nicht was benötigt wurde.
Aber mit Josuas Lösung,
%Vor%Und es funktioniert wie erwartet.
Joshua Taylor erwähnte, wie man es in Common Lisp macht. Ich werde beantworten, wie in Emacs Lisp:
%Vor%Und einige Tests:
%Vor%Makro-Erweiterungstest:
%Vor%Verwenden Sie für Makroexpand-1 und hübsches Drucken das Makrostep-Paket.
Wenn (push x lst)
als (setf lst (cons x lst))
expandiert, dann mache ein Makro prepend
so, dass der Aufruf (prepend xs lst)
als (setf lst (append xs lst))
expandiert:
Das zweite Argument muss eine Stelle bezeichnen, muss aber auch für push
gelten.
Sie müssen darauf achten, keine langwierigen Berechnungen im place -Argument zu haben, sonst:
%Vor%Tags und Links macros lisp common-lisp