Common Lisp'de "set`," setq` ve "setf` arasındaki fark nedir?


166

Common Lisp'de "set", "setq" ve "setf" arasındaki fark nedir?


9
Bunların davranışı cevaplarda oldukça iyi yanıtlanmaktadır, ancak kabul edilen cevap muhtemelen "setf" deki "f" için yanlış bir etimolojiye sahiptir. Cevabı için setf standa f neyi? "işlev" için olduğunu ve yedeklenmesi için referanslar sağladığını söylüyor.
Joshua Taylor

Yanıtlar:


169

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.


45
Ortak Lisp'in daima değişken değişkenleri vardı. Common Lisp'den önce Lisp'den bahsediyor olmalısın.
Rainer Joswig

4
SET ve SETQ, Common Lisp halefinden önyüklenecekse, bazı yedekler almaları gerekir. Yüksek seviyeli kodda kullanımları sınırlıdır, ancak düşük seviyeli kod (örneğin, SETF'in uygulandığı kod) bunlara ihtiyaç duyar.
Svante

13
araba işlevi olarak karıştırılabilecek bir şey yerine bir alan olarak 'otomobil'i seçmenizin bir nedeni var mı?
drudru

9
Bu cevap için için setf standa f neyi? Bu iddialar 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.
Joshua Taylor

1
Özet: 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.
KIM Taegyoon

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

12
Cevabınızı en çok oy alandan daha net buluyorum. Çok teşekkürler.
CDR

2
@Sourav, lütfen ASLA "l" (ell) harfini örnek kodda bir değişken ya da sembol olarak kullanmayın. 1
rakamından

Hayır, hala (araba ls) bir l değeri olabilir ya da olmayabilir nasıl anlamıyorum. CLisp'i C'ye nasıl çevireceğinizi anlıyor musunuz? ve bir CLisp tercümanı nasıl yazılır?
reuns

@ user1952009 clisp bir Common Lisp uygulamasıdır. Dilin kendisine başvurmak istiyorsanız, CL en çok kullanılan kısaltmadır.
ssice

2
@ user1952009 Sonra (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
kyle

21

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.


1
Setq adı için en mantıklı. Hatırlaması kolay. Teşekkürler.
CDR

17

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

13

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.


4

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))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.