next up previous
Next: 6 リードマクロ Up: ソフトウェア特論 講義資料 クロージャ,オブジェクト指向 Previous: 4 関数閉包(closure)

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月6日