2009-05-15 13 views
129

Qual è la differenza tra "set", "setq" e "setf" in Common Lisp?Differenza tra `set`,` setq` e `setf` in Common Lisp?

+8

Il comportamento di questi viene risposto abbastanza bene nelle risposte, ma la risposta accettata ha un'etimologia forse errata per la "f" in "setf". La risposta a [cosa significa la f in setf sta per?] (Http://stackoverflow.com/q/23808189/1281433) dice che è per "funzione", e fornisce riferimenti per il backup. –

risposta

138

In origine, in Lisp, non c'erano variabili lessicali, solo dinamiche. E non c'era SETQ o SETF, solo la funzione SET.

Quello che oggi è scritto come:

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

è stato scritto come:

(set (quote *foo*) 42) 

che finalmente è stato abbreviavated a setq (SET Citato):

(setq *foo* 42) 

variabili Poi lessicali successo e SETQ è stato utilizzato anche per l'assegnazione a questi - quindi non era più un semplice wrapper attorno a SET.

Più tardi, qualcuno ha inventato SETF (SET Field) come un modo generico di assegnazione di valori alle strutture di dati, per rispecchiare le t-valori delle altre lingue:

x.car := 42; 

sarebbe scritto come

(setf (car x) 42) 

Per simmetria e generalità, SETF ha fornito anche la funzionalità di SETQ. A questo punto sarebbe stato corretto dire che SETQ era una primitiva di basso livello, e SETF un'operazione di alto livello.

Quindi si sono verificati i simboli macro. In modo che le macro simbolo potrebbe funzionare in modo trasparente, si è capito che setq avrebbe dovuto agire come SETF se la "variabile" viene assegnato a era davvero una macro simbolo:

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

foo => 42 

(setq foo 13) 

foo => 13 

*hidden* => (13 . 42) 

Si arriva così al giorno d'oggi: SET e I SETQ sono resti atrofizzati di dialetti più vecchi e probabilmente verranno avviati da eventuali successori di Common Lisp.

+39

Common Lisp ha sempre avuto variabili lessicali. Devi parlare di alcune Lisp prima di Common Lisp. –

+4

Se SET e SETQ devono essere avviati da un successore Common Lisp, dovranno ottenere una sostituzione. Il loro uso nel codice di alto livello è limitato, ma il codice di basso livello (ad esempio, il codice SETF è implementato in) ne ha bisogno. – Svante

+12

c'è un motivo per cui hai scelto 'auto' come un campo invece di qualcosa che potrebbe essere confuso come funzione dell'automobile? – drudru

19

setq è come set con un primo argomento quotato - (set 'foo '(bar baz)) è proprio come (setq foo '(bar baz)). setf, d'altra parte, è davvero sottile - è come una "indiretta". Suggerisco http://www.n-a-n-o.com/lisp/cmucl-tutorials/LISP-tutorial-16.html come un modo migliore per iniziare a comprenderlo rispetto a qualsiasi risposta qui può dare ... in breve, però, setf prende il primo argomento come un "riferimento", così ad es. (aref myarray 3) funzionerà (come il primo argomento a setf) per impostare un elemento all'interno di un array.

+1

Ha più senso per il nome setq. Facile da ricordare. Grazie. – CDR

111
(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 
+11

Trovo che la tua risposta sia più chiara di quella votata in alto. Molte grazie. – CDR

+1

@Sourav, non utilizzare MAI la lettera "l" (ell) come variabile o simbolo nel codice di esempio. È troppo difficile distinguere visivamente dal numero 1. – DavidBooth

+0

No, non riesco ancora a capire come (auto ls) possa essere un valore l o no. Capisci come tradurre CLisp in C? e come scrivere un interprete CLisp? – reuns

4

vorrei aggiungere alle risposte precedenti, che setf è macro che chiama la funzione specifica a seconda di ciò che è stato passato come primo argomento. Confrontare i risultati della macro espansione setf con diversi tipi di argomenti:

(macroexpand '(setf a 1)) 

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

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

Per alcuni tipi di argomenti "funzione setf" si chiamerà:

(defstruct strct field) 
(macroexpand '(setf (strct-field (make-strct)) 1)) 
12

È possibile utilizzare setf al posto di set o setq ma non viceversa poiché setf può anche impostare il valore di singoli elementi di una variabile se la variabile ha singoli elementi. Vedere gli esempi di seguito:

Tutti e quattro gli esempi assegneranno la lista (1, 2, 3) alla variabile denominata foo.

(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 ha più la capacità di fissare un membro della lista in foo ad un nuovo valore.

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) 

Tuttavia, è possibile definire una macro simbolo che reprents un singolo elemento all'interno foo

(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) 

È possibile utilizzare defvar se non l'hai già definito la variabile e non si vuole dare un valore fino a tardi nel tuo codice.

(defvar foo2) 
(define-symbol-macro foo-car (car foo2)) 
6

Si può pensare SET e SETQ essere costrutti a basso livello.

  • SET possibile impostare il valore di simboli.

  • SETQ può impostare il valore delle variabili.

Poi SETF è una macro, che fornisce molti tipi di regolazione cose: simboli, variabili, elementi dell'array, slot istanza, ...

Per i simboli e variabili si può pensare come se SETF espande in SET e SETQ.

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

(SET 'A 10) 


* (macroexpand '(setf a 10))   

(SETQ A 10) 

Così SET e SETQ vengono utilizzate per implementare alcune delle funzionalità di SETF, che è il costrutto più generale. Alcune delle altre risposte ti dicono la storia un po 'più complessa, quando prendiamo in considerazione le macro dei simboli.