Next: , Previous: , Up: Variable Scoping   [Contents][Index]


11.9.3 Lexical Binding

Emacsのバージョン24.1から、オプションの機能としてレキシカルバインディングが導入されました。わたしたちは、この機能の重要さが、将来において重要になることを期待します。レキシカルバインディングは最適化の機会をより広げるので、この機能を使用するプログラムはおそらく、将来のEmacsバージョンで高速に実行されるようになるでしょう。レキシカルバインディングは、わたしたちが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層化し、増加された値をreturnするクロージャーを定義しています。このラムダ式は自動的にクロージャーになり、たとえlet構造を抜けた後でも、その内部ではレキシカル環境が存続します。クロージャーを評価するときは毎回、レキシカル環境内のxのバインディングが使用され、xが増加されます。

symbol-valueboundpsetのような関数は、変数のダイナミックバインディング(つまりそのシンボルの値セル)だけを取得(または変更)することに注意してください。defun(またはdefmacro)のbody内のコードも、周囲のレキシカル変数は参照できません。