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.
faslı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.
setbir işlevdir. Böylece çevreyi bilmiyor. setsözlük değişkenini göremiyorum. Bağımsız değişkeninin yalnızca sembol değerini ayarlayabilir. setqartı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 lssabit 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 = 5C.'de olduğu gibi çalışır
setqgibi bulun setbir 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, setfsü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 setfyerine setya setqama tersi beri setfdeğ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)
setflistenin bir üyesini fooyeni 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 defvarzaten 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 SETve SETQdüşük seviyeli yapıları olmak.
SET sembollerin değerini ayarlayabilir.
SETQ değişkenlerin değerini ayarlayabilir.
Öyleyse SETFbirç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 SETFgenişletir içine SETve SETQ.
* (macroexpand '(setf (symbol-value 'a) 10))
(SET 'A 10)
* (macroexpand '(setf a 10))
(SETQ A 10)
Böylece SETve daha genel bir yapı olan SETQbazı 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))