Common Lispの「set」、「setq」、「setf」の違いは何ですか?
6 に答える
もともと、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は古い方言の萎縮した残骸であり、おそらくCommonLispの後継者から起動されるでしょう。
(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
変数に個々の要素がある場合は、変数の個々の要素の値を設定することもできるためsetf
、の代わりに使用できますset
がsetq
、その逆はできません。setf
以下の例を参照してください。
4つの例すべてで、リスト(1、2、3)がfooという名前の変数に割り当てられます。
(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))
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 は、最初の引数として渡されたものに応じて特定の関数を呼び出すマクロであるという以前の回答に追加したいと思います。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))