Common Lispの `set`、` setq`、 `setf`の違いは?


166

Common Lispの「set」、「setq」、および「setf」の違いは何ですか?


9
これらの動作は回答でかなりよく回答されていますが、受け入れられた回答には、「setf」の「f」の語源が誤っている可能性があります。答えのためのsetfスタンドでfは何?それは「関数」のためであると言い、それをバックアップするためのリファレンスを提供します。
ジョシュアテイラー

回答:


169

もともと、Lispでは、字句変数はなく、動的変数のみでした。そして、SETQやSETFはなく、SET関数だけがありました。

現在は次のように書かれています:

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

として書かれた:

(set (quote *foo*) 42)

これは最終的にSETQ(SET Quoted)に省略されました。

(setq *foo* 42)

その後、字句変数が発生し、SETQもそれらへの割り当てに使用されるようになりました。そのため、SETの単純なラッパーではなくなりました。

その後、他の言語のl値を反映するために、データ構造に値を割り当てる一般的な方法としてSETF(SETフィールド)が発明されました。

x.car := 42;

と書かれる

(setf (car x) 42)

対称性と一般性のために、SETFはSETQの機能も提供しました。この時点で、SETQは低レベルのプリミティブであり、SETFは高レベルの操作であると言ったほうが正しいでしょう。

その後、シンボルマクロが発生しました。シンボルマクロが透過的に機能するように、割り当てられている「変数」が実際にシンボルマクロである場合、SETQはSETFのように動作する必要があることがわかりました。

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

foo => 42

(setq foo 13)

foo => 13

*hidden* => (13 . 42)

だから私たちは今日に到着します:SETとSETQは古い方言の萎縮した遺跡であり、おそらくCommon Lispの後継者から起動されるでしょう。


45
Common Lispには常に字句変数がありました。Common Lispの前に、いくつかのLispについて話している必要があります。
Rainer Joswig、2009年

4
SETとSETQをCommon Lispの後継からブートする場合は、それらを置き換える必要があります。高レベルのコードでの使用は制限されていますが、低レベルのコード(たとえば、SETFが実装されているコード)では必要です。
Svante、

13
車の機能と混同される可能性のあるものではなく、フィールドとして「車」を選択した理由はありますか?
drudru

9
この回答のためのsetfスタンドでfは何?は、f実際にはフィールド(またはフォーム)ではなく関数を表し、参照を提供すると主張しているため、フィールドのsetfはある程度の意味を持っていますが、正しくない可能性があります。
ジョシュアテイラー

1
概要:setは関数です。したがって、それは環境を知りません。setレキシカル変数が見えません。引数のシンボル値のみを設定できます。setq「引用符で囲まれたセット」ではなくなりました。setqマクロではなく特別な形式であるという事実は、それを示しています。
KIMテギョン2018

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
私はあなたの答えがトップ投票されたものより明確であると思います。どうもありがとう。
CDR

2
@Sourav、コード例では変数または記号として文字「l」(エル)を使用しないでください。数字の1と視覚的に区別するのは難しすぎる
DavidBooth

いいえ、まだ(車のls)がl値になるかどうかはわかりません。CLispをCに変換する方法を理解していますか?CLispインタープリターの書き方は?
2015年

@ user1952009 clispは、Common Lispの実装の1つです。言語自体を参照したい場合は、CLが最もよく使われる略語です。
ssice

2
@ user1952009後は(setq ls '(((1))))(setf (car (car (car ls))) 5)の値があるため、未定義の動作であるls(Cの文字列リテラルを変更するような)定数です。後(setq ls (list (list (list 1))))(setf (car (car (car ls))) 5)同じように動作しますls->val->val->val = 5C.で
カイル

21

setqset最初の引数を引用符で囲んだのと(set 'foo '(bar baz))同じ(setq foo '(bar baz))です。setf一方、実際には微妙です-「間接」のようなものです。私が提案するhttp://www.nano.com/lisp/cmucl-tutorials/LISP-tutorial-16.htmlがより良い方法は、任意の答えよりも、それを理解し始めるために、ここで与えることができます...要するに、しかし、setfとり「参照」としての最初の引数。たとえば、配列内の項目を設定する(aref myarray 3)ために(最初の引数としてsetf)機能します。


1
setq名に最も意味があります。覚えやすい。ありがとう。
CDR

17

変数に個別の要素がある場合、変数の個別の要素の値を設定することもできるためsetf、の代わりに、setまたはsetqその逆は使用できますsetf。以下の例をご覧ください。

4つの例はすべて、fooという名前の変数にリスト(1、2、3)を割り当てます。

(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リストのメンバーをfoo新しい値に設定する追加機能があります。

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)

ただし、内部で単一のアイテムを表すシンボルマクロを定義できます。 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)

defvar変数をまだ定義しておらず、コードの後半まで値を設定したくない場合に使用できます。

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

13

低レベルの構造SETと考えることができますSETQ

  • SET シンボルの値を設定できます。

  • SETQ 変数の値を設定できます。

次にSETF、シンボル、変数、配列要素、インスタンススロットなど、さまざまな設定項目を提供するマクロがあります。

記号と変数の一つは、ifのように考えることができますSETFに展開をSETしてSETQ

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

(SET 'A 10)


* (macroexpand '(setf a 10))         

(SETQ A 10)

したがってSET、およびは、より一般的な構成SETQであるの機能の一部を実装するために使用されSETFます。他の回答のいくつかは、シンボルマクロを考慮に入れると、少し複雑な話をします。


4

以前の回答に加えて、setfは最初の引数として渡されたものに応じて特定の関数を呼び出すマクロであることを追加したいと思います。setfのマクロ展開の結果をさまざまなタイプの引数と比較します。

(macroexpand '(setf a 1))

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

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

一部のタイプの引数では、「setf関数」が呼び出されます。

(defstruct strct field)
(macroexpand '(setf (strct-field (make-strct)) 1))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.