was ist anzusetzen, wie Push ist, um Nachteile, in Lisp?

9
%Vor%

wird zu

erweitert %Vor%

Was erweitert sich zu dem folgenden:

%Vor%

? Gibt es dafür ein Standardmakro?

    
Le Curious 28.07.2013, 13:11
quelle

5 Antworten

16

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.

Verwendung von 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 :

verwenden %Vor%

Wenn Sie swapped-append nicht als Funktion definieren möchten, können Sie lambda -Ausdruck auf define-modify-macro :

setzen %Vor%

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 :

%Vor%

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.

Verwendung von get-setf-expansion

Die Argumente von

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 um die Setf-Erweiterung sicher für den Ort zu erhalten und Mehrfachbewertungen zu vermeiden.

%Vor%

Die Verwendung von get-setf-expansion bedeutet, dass dieses Makro auch an komplizierteren Orten funktioniert:

%Vor%

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:

%Vor%     
Joshua Taylor 28.07.2013, 18:47
quelle
3

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.

    
user1220978 29.07.2013 07:17
quelle
2

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.

    
Jisang Yoo 30.07.2013 03:55
quelle
1

Soweit ich weiß, gibt es nichts Fertiges, aber es sollte relativ einfach sein, eins zu machen.

%Vor%     
Vatine 28.07.2013 14:05
quelle
1

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:

%Vor%

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%     
Will Ness 29.07.2013 13:31
quelle

Tags und Links