スコープ

すべてのsymbolは、値と結び付いている。 symbolは、主にくくられた文脈から決定される値によって評価される。 ここに2種類の変数バインドがある。それは、 ローカルまたは静的バインドとスペシャルまたは動的バインドである。 ローカルにバインドされた変数はlambda書式または letlet*の特殊書式においてspecialと宣言されない限り 外から見ることはできない。 ローカルバインドは入れ子が可能で、外側のローカルバインドやスペシャルバインドを隠して、 最も内側のレベルで定義されている1つのバインドのみ見ることができる。 スペシャル変数は2つの方法で使用される。 1つは、グローバル変数として、もう1つは動的に覗けるローカル変数として用いる。 このローカル変数は、バインドの効果の中にある限りローカルスコープの 外にいてさえ見ることができる。 後者の場合、スペシャル変数はspecialで宣言される必要がある。 その宣言は、コンパイラだけでなくインタプリタでも認識される。 Common Lispによると、スペシャル変数は不明瞭なスコープと動的な 広さを持っていると言われている。

あるスコープのなかで、ローカル変数が存在するとしても、 同じ変数名を内部スコープの中でspecialとして再宣言することができる。 symbol-value関数は、ローカルスコープに構わずspecial値を引き出す ために使用することができる。 set関数は、スペシャル変数としてのみ働く。すなわち、 specialとして宣言していない限り、lambdaやlet変数の値を 変更するために使用することはできない。

(let ((x 1))
   (declare (special x))
   (let* ((x (+ x x)) (y x))
      (let* ((y (+ y y)) (z (+ x x)))
         (declare (special x))
         (format t "x=~S y=~s z=~s~%" x y z) ) ) )
--> x=1 y=4 z=2

symbolは、defconstantマクロにより定数として宣言することができる。 一旦宣言すると、その後値を変更しようとするとエラーが発生する。 そのうえ、そのような定数symbolは、ローカル変数としてさえ変数名として 使用されることを禁じられる。 NILやTは、そのような定数の例である。 keywordパッケージのsymbolは、いつも作成されるときに定数として宣言される。 対照的に、defvardefparameterマクロは、スペシャル変数として symbolを宣言する。 defvarは、symbolがバインドされていない時のみ値の初期化を行い、 値が既に割り当てられているときは何もしない。 それに対して、defparameterはいつも値をリセットする。

symbolが参照され、symbolのためのローカルバインドがなかったとき、 そのspecial値は、引き出される。 しかしながら、そのspecial値にまだ値が割り当ててなかったならば、 unbound variableエラーが発生する。



2016-04-05