Common Lispの「set」、「setq」、および「setf」の違いは何ですか?
Common Lispの「set」、「setq」、および「setf」の違いは何ですか?
回答:
もともと、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の後継者から起動されるでしょう。
f
実際にはフィールド(またはフォーム)ではなく関数を表し、参照を提供すると主張しているため、フィールドのsetfはある程度の意味を持っていますが、正しくない可能性があります。
set
は関数です。したがって、それは環境を知りません。set
レキシカル変数が見えません。引数のシンボル値のみを設定できます。setq
「引用符で囲まれたセット」ではなくなりました。setq
マクロではなく特別な形式であるという事実は、それを示しています。
(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)
の値があるため、未定義の動作であるls
(Cの文字列リテラルを変更するような)定数です。後(setq ls (list (list (list 1))))
、(setf (car (car (car ls))) 5)
同じように動作しますls->val->val->val = 5
C.で
setq
set
最初の引数を引用符で囲んだのと(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
)機能します。
変数に個別の要素がある場合、変数の個別の要素の値を設定することもできるため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))
低レベルの構造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
ます。他の回答のいくつかは、シンボルマクロを考慮に入れると、少し複雑な話をします。
以前の回答に加えて、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))