Next: Using Lexical Binding, Previous: Dynamic Binding Tips, Up: Variable Scoping [Contents][Index]
Emacsのバージョン24.1からオプションの機能としてレキシカルバインディングが導入されました。わたしたちはこの機能の重要性が時とともに増加することを期待します。レキシカルバインディングは最適化の機会をより広げるので、この機能を使用するプログラムはおそらく将来のEmacsバージョンで高速に実行されるようになるでしょう。レキシカルバインディングは、わたしたちがバージョン26。1のEmacsで追加した並列性(concurrency)とも互換があります。
レキシカルにバインドされた変数はレキシカルスコープ(lexical scope)をもちます。これはその変数にたいする参照が、そのバインディング構文内にテキスト的に配置されなければならないことを意味しています。以下は例です (実際にレキシカルバインディングを有功にする方法は、Using Lexical Bindingを参照のこと):
(let ((x 1)) ;x
はレキシカルにバインドされる (+ x 3)) ⇒ 4 (defun getx () x) ; この関数内ではx
は自由に使用される (let ((x 1)) ;x
はレキシカルにバインドされる (getx)) error→ Symbol's value as variable is void: x
ここではx
はグローバル値をもちません。let
フォーム内でレキシカルにバインドされたとき、この変数はlet
のテキスト境界内で使用できます。しかしこのlet
内から呼び出されるgetx
関数からは、getx
の関数定義がlet
フォームの外側なので使用することができません。
レキシカルバインディングが機能する方法を説明します。バインディング構文はぞれぞれ、その構文内でローカル値にバインドする変数を指定する、レキシカル環境(lexical environment)を定義します。Lispの評価機能(Lisp evaluator)が、ある変数のカレント値を得たいときは、最初にレキシカル環境内を探します。そこで変数が指定されていなければ、ダイナミック値が格納されるシンボルの値セルを探します。
(内部的にはレキシカル環境はシンボルと値がペアになったalistでり、alistの最後の要素はコンスセルではなくシンボルt
である。そのようなalistはフォームを評価するためのレキシカル環境を指定するために、eval
関数の2番目の引数として渡すことができる。Evalを参照のこと。しかしほとんどのEmacs
Lispプログラムは、この方法で直接レキシカル環境を使用するべきではない。デバッガーのような特化されたプログラムだけが使用すること。)
レキシカルバインディングは不定エクステント(indefinite extent)をもちます。バインディング構造が終了した後でも、そのレキシカル環境はクロージャー(closures)と呼ばれるLispオブジェクト内に“保持”されるかもしれ、あせん。クロージャーはレキシカルバインディングが有効な、名前つきまたは無名(anonymous)の関数が作成されたときに作成されます。詳細はClosuresを参照してください。
クロージャーが関数として呼び出されたとき、その関数の定義内のレキシカル変数にたいする任意の参照は、維持されたレキシカル環境を使用します。以下は例です:
(defvar my-ticker nil) ; クロージャーを格納するために ; この変数を使用する (let ((x 0)) ;x
はレキシカルにバインドされる (setq my-ticker (lambda () (setq x (1+ x))))) ⇒ (closure ((x . 0) t) () (setq x (1+ x))) (funcall my-ticker) ⇒ 1 (funcall my-ticker) ⇒ 2 (funcall my-ticker) ⇒ 3 x ;x
はグローバル値をもたないことに注意 error→ Symbol's value as variable is void: x
let
バインディングは、内部に変数x
をもつレキシカル環境を定義して、変数は0にローカルにバインドされます。このバインディング構文内でx
を1増加して、増加された値をリターンするクロージャーを定義しています。このラムダ式は自動的にクロージャーとなり、たとえlet
構文を抜けた後でも、その内部ではレキシカル環境が存続します。クロージャーを評価するときは、毎回レキシカル環境内のx
のバインディングが使用されて、x
が加算されます。
シンボルオブジェクト自体に束縛されるダイナミック変数と異なり、レキシカル変数とシンボルの関係はインタープリター(かコンパイラー)内にのみ存在します。したがって(symbol-value
、boundp
、set
のような)シンボル引数を受け取る関数ができるのは、変数のダイナミックなバインディング(そのシンボルの値セルの内容)の取得と変更だけです。