next up previous
Next: 6 リードマクロ Up: ソフトウェア第三 講義資料 クロージャ,スコープ,遅延評価,オブジェクト,立体モデル Previous: 4.3 クロージャを返す関数の例

5 スコープ,バインディング,エクステント

変数の参照可能な範囲のことをスコープと呼ぶ.変数のスコープの 外ではその変数へアクセスできない.たとえば,defunの定義の引数のスコー プはその定義本体の中だけである. 局所変数(local variable)とは,スコープが限定されている変数のこ とで,局所変数のスコープはレキシカルスコープ(lexical scope)であ るという. スコープが限定されていない変数は大域変数(global variable)と呼ば れ,大域変数のスコープは無限スコープ(indefinite scope)と呼ばれる. 変数に値をもたせることをバインディング(binding)と呼ぶ.局所変数の バインディングは静的バインディング(static binding)と呼ばれ,大域 変数のバインディングは動的バインデイング(dynamic binding)と呼ば れる. バインディングの生存期間(時間的な範囲)はエクステント(extent)と いう. 静的なバインディングはクロージャの中に残る限りいつでも参照できるので 無限のエクステント(indefinite extent)をもつという.動的なバイ ンディングはフォームの実行の間だけしか参照できないので動的なエクス テント(dynamic extent)をもつといえる. 変数がスペシャル(special)というのは動的バインディングがおこる変 数のことをいう.大域変数はスペシャル変数である. CommonLispではdefvar, defparameterなどで宣言した変数はスペシャル変数と なる. たとえば,

% acl
Allegro CL 3.0.1.beta [sun4] (12/12/90 11:16)
Copyright (C) 1985-1988, Franz Inc., Berkeley, CA, USA
> (defun test1 (x) (test2))
TEST1 
> (defun test2 () (print x))
TEST2 
> (test1 2)
Error: Attempt to take the value of the unbound symbol X
[1] > :reset
というように,変数xはtest1の関数の局所変数でtest2の定義内部までのスコー プを持たない.そのため,関数test2の本体を実行する際のxは大域変数と扱 われるが,今の場合大域変数xは値を持たないためにunboundエラーが起こる. そこで,次にdefvarによりxをスペシャル変数として宣言してtest1を呼ぶと,

> (defvar x 10)
X 
> (test1 2)
2 
2 
> x
10
となる.ここで注意しなければならないのは,test1の引数 x はスペシャ ル変数であるために動的バィンディングが起こる.そのためxの値は2に一 端なるが,その関数から抜けでるとその値との結合を解除しxは元の値 (10)に戻る. 処理系全体でスペシャル変数を宣言するのではなく,関数の内部で局所的に スペシャル宣言をするための方法もある.declare を使う. 以下のようにtest3の引数であるyという変数をその本体の内部でスペシャルで ある(動的バインディングを行なうように)と宣言すれば,test4の中の変数y は動的バインディングされた値を利用してtest3の引数の値を用いることが出 来るようになる.

> (defun test3 (y) (declare (special y)) (test4))
test3

>(defun test4 () (print y))
test4

> y

*** - EVAL: variable Y has no value
1. Break > :uw

> (test3 2)
2 
2
[27]> (test4)
*** - EVAL: variable Y has no value
1. Break > :uw
[29]> y
*** - EVAL: variable Y has no value
1. Break > :uw
このようにtest3の実行後にはyの値はもとにもどりunboundになっている.

generated through LaTeX2HTML. M.Inaba 平成18年5月7日