it-swarm.com.de

Unterschied zwischen `set`,` setq` und `setf` in Common Lisp?

Was ist der Unterschied zwischen "set", "setq" und "setf" in Common Lisp?

155
Richard Hoskins

Ursprünglich gab es in LISP keine lexikalischen Variablen - nur dynamische. Und es gab kein SETQ oder SETF, nur die SET-Funktion.

Was jetzt geschrieben steht als:

(setf (symbol-value '*foo*) 42)

wurde geschrieben als:

(set (quote *foo*) 42)

was schließlich zu SETQ abgekürzt wurde (SET Quoted):

(setq *foo* 42)

Dann passierten lexikalische Variablen und SETQ wurde auch für deren Zuweisung verwendet - es war also kein einfacher Wrapper mehr um SET.

Später erfand jemand SETF (SET Field) als eine generische Methode, Datenstrukturen Werte zuzuweisen, um die l-Werte anderer Sprachen zu spiegeln:

x.car := 42;

würde geschrieben werden als

(setf (car x) 42)

Aus Gründen der Symmetrie und Allgemeinheit stellte SETF auch die Funktionalität von SETQ zur Verfügung. Zu diesem Zeitpunkt wäre es richtig gewesen zu sagen, dass SETQ ein Grundelement auf niedriger Ebene und SETF eine Operation auf hoher Ebene war.

Dann geschahen Symbolmakros. Damit Symbolmakros transparent arbeiten können, wurde erkannt, dass SETQ sich wie SETF verhalten muss, wenn die zugewiesene "Variable" wirklich ein Symbolmakro ist:

(defvar *hidden* (cons 42 42))
(define-symbol-macro foo (car *hidden*))

foo => 42

(setq foo 13)

foo => 13

*hidden* => (13 . 42)

Wir kommen also in der Gegenwart an: SET und SETQ sind verkümmerte Überreste älterer Dialekte und werden wahrscheinlich von späteren Nachfolgern von Common LISP gebootet.

161
(set ls '(1 2 3 4)) => Error - ls has no value

(set 'ls '(1 2 3 4)) => OK

(setq ls '(1 2 3 4)) => OK - make ls to (quote ls) and then have the usual set

(setf ls '(1 2 3 4)) => OK - same as setq so far BUT

(setf (car ls) 10) => Makes ls '(10 2 3 4) - not duplicated by setq/set
130
Sourav

setq ist genau wie set mit einem ersten Argument in Anführungszeichen - (set 'foo '(bar baz)) ist genau wie (setq foo '(bar baz)). setf dagegen ist in der Tat subtil - es ist wie eine "Indirektion". Ich empfehle http://www.nano.com/LISP/cmucl-tutorials/LISP-tutorial-16.html , um besser damit zu beginnen, es zu verstehen, als jede Antwort hier geben kann ... kurz gesagt, setf nimmt das erste Argument als "Referenz", so dass z (aref myarray 3) funktioniert (als erstes Argument für setf), um ein Element innerhalb eines Arrays festzulegen.

21
Alex Martelli

Sie können setf anstelle von set oder setq verwenden, aber nicht umgekehrt, da setf auch den Wert einzelner Elemente einer Variablen festlegen kann, wenn die Variable hat einzelne Elemente. Siehe die Beispiele unten:

Alle vier Beispiele weisen der Variablen foo die Liste (1, 2, 3) zu.

(set (quote foo) (list 1 2 3))    ;foo => (1 2 3)
(1 2 3)

(set 'foo '(1 2 3))   ;foo => (1 2 3) same function, simpler expression
(1 2 3)

(setq foo '(1 2 3))   ;foo => (1 2 3) similar function, different syntax
(1 2 3)

(setf foo '(1 2 3))   ;foo => (1 2 3) more capable function
(1 2 3)

setf kann jetzt ein Mitglied der Liste in foo auf einen neuen Wert setzen.

foo                   ;foo => (1 2 3) as defined above
(1 2 3)

(car foo)             ;the first item in foo is 1
1

(setf (car foo) 4)    ;set or setq will fail since (car foo) is not a symbol
4

foo                   ;the fist item in foo was set to 4 by setf
(4 2 3)

Sie können jedoch ein Symbolmakro definieren, das ein einzelnes Element in foo darstellt.

(define-symbol-macro foo-car (car foo))    ; assumes FOO => (1 2 3)
FOO-CAR

foo-car               ;foo-car is now a symbol for the 1st item in foo
1

(setq foo-car 4)      ;set or setq can set the symbol foo-car 
4

foo                   ;LISP macros are so cool
(4 2 3)

Sie können defvar verwenden, wenn Sie die Variable noch nicht definiert haben und sie erst später in Ihrem Code mit einem Wert versehen möchten.

(defvar foo2)
(define-symbol-macro foo-car (car foo2))
16
dansalmo

Man kann sich SET und SETQ als Konstrukte auf niedriger Ebene vorstellen.

  • SET kann den Wert von Symbolen festlegen.

  • SETQ kann den Wert von Variablen festlegen.

Dann ist SETF ein Makro, das viele Arten von Einstellungsmöglichkeiten bietet: Symbole, Variablen, Array-Elemente, Instanz-Slots, ...

Bei Symbolen und Variablen kann man denken, dass SETF in SET und SETQ expandiert.

* (macroexpand '(setf (symbol-value 'a) 10))

(SET 'A 10)


* (macroexpand '(setf a 10))         

(SETQ A 10)

Also werden SET und SETQ verwendet, um einige der Funktionen von SETF zu implementieren, was das allgemeinere Konstrukt ist. Einige der anderen Antworten erzählen Ihnen die etwas komplexere Geschichte, wenn wir Symbolmakros berücksichtigen.

12
Rainer Joswig

Zu den vorherigen Antworten möchte ich hinzufügen, dass setf ein Makro ist, das abhängig von dem, was als erstes Argument übergeben wurde, eine bestimmte Funktion aufruft. Vergleichen Sie die Ergebnisse der Makroexpansion von setf mit verschiedenen Argumenttypen:

(macroexpand '(setf a 1))

(macroexpand '(setf (car (list 3 2 1)) 1))

(macroexpand '(setf (aref #(3 2 1) 0) 1))

Für einige Arten von Argumenten wird "setf function" aufgerufen:

(defstruct strct field)
(macroexpand '(setf (strct-field (make-strct)) 1))
4
Filipp