web-dev-qa-db-ja.com

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

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

155
Richard Hoskins

もともと、LISPには字句変数はなく、動的変数のみがありました。また、SET機能もSETQもSETFもありませんでした。

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

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

として書かれた:

(set (quote *foo*) 42)

最終的にはSETQに短縮されました(SET Quoted):

(setq *foo* 42)

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

後に、誰かが、他の言語のl値をミラーリングするために、データ構造に値を割り当てる一般的な方法としてSETF(SET Field)を発明しました:

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の後継者からブートされるでしょう。

161
(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
130
Sourav

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への最初の引数として)動作し、配列内に項目を設定します。

21
Alex Martelli

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

SETおよびSETQは低レベルの構成体であると考えることができます。

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

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

SETFはマクロであり、シンボル、変数、配列要素、インスタンススロットなど、多くの種類の設定項目を提供します。

シンボルと変数については、SETFSETSETQに展開されるように考えることができます。

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

(SET 'A 10)


* (macroexpand '(setf a 10))         

(SETQ A 10)

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

12
Rainer Joswig

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