Common Lisp'de "set", "setq" ve "setf" arasındaki fark nedir?
Common Lisp'de "set", "setq" ve "setf" arasındaki fark nedir?
Yanıtlar:
Başlangıçta Lisp'te sözlüksel değişkenler yoktu - sadece dinamik değişkenler. Ve SETQ ya da SETF yoktu, sadece SET fonksiyonu vardı.
Şimdi ne yazıyor:
(setf (symbol-value '*foo*) 42)
şu şekilde yazılmıştır:
(set (quote *foo*) 42)
en sonunda SETQ olarak kısaltılmıştır (SET Quoted):
(setq *foo* 42)
Sonra sözcük değişkenleri oldu ve SETQ da onlara atama için kullanılmaya başladı - bu yüzden artık SET'in etrafında basit bir paket değildi.
Daha sonra, birisi SETF'yi (SET Alanı), diğer dillerin l değerlerini yansıtmak için veri yapılarına değer atamanın genel bir yolu olarak icat etti:
x.car := 42;
olarak yazılır
(setf (car x) 42)
Simetri ve genellik için SETF aynı zamanda SETQ'nun işlevselliğini de sağlamıştır. Bu noktada SETQ'nun Düşük seviyeli bir ilkel olduğunu ve SETF'in yüksek seviyeli bir operasyon olduğunu söylemek doğru olurdu.
Sonra sembol makroları oldu. Bu sembol makroları şeffaf bir şekilde çalışabilir, eğer atanan "değişken" gerçekten bir sembol makrosu ise SETQ'nun SETF gibi davranması gerektiği anlaşıldı:
(defvar *hidden* (cons 42 42))
(define-symbol-macro foo (car *hidden*))
foo => 42
(setq foo 13)
foo => 13
*hidden* => (13 . 42)
Bu yüzden günümüze varıyoruz: SET ve SETQ, eski lehçelerin atrofiye kalıntılarıdır ve muhtemelen Common Lisp'in nihai haleflerinden önyüklenecektir.
f
aslında açılımı fonksiyonu değil, sahada (veya formun alan için setf bazı mantıklı ederken doğru olmayabilir gibi bu konuda,), ve referanslar içerir, böylece görünüyor.
set
bir işlevdir. Böylece çevreyi bilmiyor. set
sözlük değişkenini göremiyorum. Bağımsız değişkeninin yalnızca sembol değerini ayarlayabilir. setq
artık "tırnak içine alınmış" değildir. Aslında setq
özel bir formu, bir makro gösterir olmasıdır.
(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
(setq ls '(((1))))
, (setf (car (car (car ls))) 5)
değeri ls
sabit olduğundan (C'de bir dize değişmez değeri değiştirmek gibi) tanımsız bir davranıştır . Sonra (setq ls (list (list (list 1))))
, (setf (car (car (car ls))) 5)
tıpkı ls->val->val->val = 5
C.'de olduğu gibi çalışır
setq
gibi bulun set
bir alıntı ilkine ile - (set 'foo '(bar baz))
gibi bulun (setq foo '(bar baz))
. setf
Öte yandan, gerçekten ince - bir "dolaylı" gibi. Ben önermek http://www.nano.com/lisp/cmucl-tutorials/LISP-tutorial-16.html daha iyi bir yolu herhangi bir cevap daha bunu anlamak başlamak için burada verebilir ... kısacası olsa da, setf
sürer ilk bağımsız değişkeni "başvuru" olarak alır, böylece örneğin bir dizi içindeki bir öğeyi ayarlamak için (aref myarray 3)
( ilk bağımsız değişken olarak) çalışır setf
.
Sen kullanabilirsiniz setf
yerine set
ya setq
ama tersi beri setf
değişken tek tek öğeleri varsa aynı zamanda bir değişkenin tek tek elemanların değer ayarlayabilirsiniz. Aşağıdaki örneklere bakın:
Dört örneğin tamamı, foo adlı değişkene listeyi (1, 2, 3) atar.
(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
listenin bir üyesini foo
yeni bir değere ayarlama özelliğine sahiptir .
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)
Ancak, içindeki tek bir öğeyi yeniden temsil eden bir sembol makrosu tanımlayabilirsiniz 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)
Sen kullanabilirsiniz defvar
zaten değişken tanımlı değil ve daha sonra kodunuzu kadar ona değer vermek istemiyorsanız.
(defvar foo2)
(define-symbol-macro foo-car (car foo2))
Bir düşünebiliriz SET
ve SETQ
düşük seviyeli yapıları olmak.
SET
sembollerin değerini ayarlayabilir.
SETQ
değişkenlerin değerini ayarlayabilir.
Öyleyse SETF
birçok çeşit ayar sağlayan bir makro var: semboller, değişkenler, dizi elemanları, örnek yuvaları, ...
Semboller ve değişkenler için tek sanki düşünebiliriz SETF
genişletir içine SET
ve SETQ
.
* (macroexpand '(setf (symbol-value 'a) 10))
(SET 'A 10)
* (macroexpand '(setf a 10))
(SETQ A 10)
Böylece SET
ve daha genel bir yapı olan SETQ
bazı işlevlerini uygulamak için kullanılır SETF
. Diğer cevaplardan bazıları, sembol makrolarını dikkate aldığımızda biraz daha karmaşık bir hikaye anlatıyor.
Setf ilk argüman olarak geçirilen bağlı olarak belirli bir işlevi çağıran makro olan önceki cevaplara eklemek istiyorum. Setf'in makro genişletmesinin sonuçlarını farklı argüman türleriyle karşılaştırın:
(macroexpand '(setf a 1))
(macroexpand '(setf (car (list 3 2 1)) 1))
(macroexpand '(setf (aref #(3 2 1) 0) 1))
Bazı argüman türleri için "setf function" çağrılır:
(defstruct strct field)
(macroexpand '(setf (strct-field (make-strct)) 1))