同様の質問 が見つかりました。
しかし、その説明はよくわかりません。
だから私は次の例でclispを実行しようとしています:
[1]> (defvar a 5)
A
[2]> (+ a 1)
6
[3]> (defparameter b 5)
B
[4]> (+ b 1)
6
[5]> (setf c 5)
5
[6]> (+ c 1)
6
[7]> (setq d 5)
5
[8]> (+ d 1)
6
[9]> (let ((a 500)) (+ a 1))
501
[10]> (let ((b 500)) (+ b 1))
501
[11]> (let ((c 500)) (+ c 1))
501
[12]> (let ((d 500)) (+ d 1))
501
[13]>
私が見つけたものは全く同じです。
彼らと何が違うのか分かりませんか?
DEFPARAMETERは常に値を割り当てます。そう:
[1]> (defparameter a 1)
A
[2]> (defparameter a 2)
A
[3]> a
2
dEFVARは一度だけそれを行うので、
[4]> (defvar b 1)
B
[5]> (defvar b 2)
B
[6]> b
1
SETFは、SETQを内部で使用するマクロですが、より多くの可能性があります。ある意味では、より一般的な代入演算子です。例えば。 SETFでできること:
[19]> (defparameter c (list 1 2 3))
[21]> (setf (car c) 42)
42
[22]> c
(42 2 3)
しかし、SETQではそれを行うことはできません。
[23]> (setq (car c) 42)
*** - SETQ: (CAR C) is not a symbol
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead.
ABORT :R2 Abort main loop
Break 1 [24]> abort
defvar
とdefparameter
はどちらも、変数を「動的スコープ変数」として宣言します。さらに、defparameter
は常に、変数の値を2番目の引数として渡した値に設定します。これはdefvar
とは異なり、以前に設定されていない場合にのみ変数の値を設定します。
グローバル字句スコープでsetf
またはsetq
を使用して変数を定義することは定義されていません。一部の実装では、動的にスコープされる変数が作成されますが、作成されないものもあります。初めて実行すると、診断メッセージが表示される場合があります。
字句スコープと動的スコープの変数の違いを理解するには、次のコードスニペットを試してください。
* (defvar *a* 1)
*A*
* (let ((*a* 5)) (defun demo-a () *a*))
DEMO-A
* (let ((b 5)) (defun demo-b () b))
DEMO-B
* (let ((*a* 100)) (demo-a))
100
* (let ((b 100)) (demo-b))
5
ここでは、動的スコープの変数と値を返す関数を作成します(関数の作成中に値が異なるバインディング内で定義されます。これは必要ではなく、bの字句閉包に似ているためだけに行われます)。次に、新しい変数を定義し、その値を返す関数を定義します。
その後、同じ名前の変数に値をバインドするクロージャ内で両方の関数を呼び出します。動的スコープの場合、同じ変数です。字句閉包のケース(b)では、2つの異なる字句閉包で定義されているため、名前は同じですが、同じ変数ではありません。
setf
とsetq
の違いについては、常にsetf
を使用するようにしてください((setq blah blahblah)
は機能し、(setf blah blahblah)
は同じことをしません)。