グローバル変数の値は、明示的に新しい値で上書きされるまで保持されます。場合によっては、変数にローカル値――Lispプログラムの特定の範囲内でのみ有効となる値――を持たせることが有用なことがあります。変数がローカル値を持つとき、その変数はその値にローカルに束縛されていると言い、またローカル変数であると言います。
例えば、関数が呼び出されると、その引数変数にはローカル値(関数呼び出しに渡された実引数)が代入され、これらのローカル束縛は関数本体内で有効になります。別の例を挙げると、let 特殊形式は特定の変数に対して明示的にローカル束縛を確立し、これは let 形式の本体内でのみ有効となります。
また、(概念的に)グローバル値が保持される場所であるグローバルバインディングについても述べます。
ローカルバインディングを定義すると、変数の以前の値(あるいは値がないこと)が保存されます。この以前の値をシャドウイングされたと言います。グローバル値とローカル値のどちらもシャドウイングされる可能性があります。ローカルバインディングが有効な状態で、ローカル変数にsetqを使用すると、指定された値がそのローカルバインディングに格納されます。そのローカルバインディングが無効になると、以前にシャドウイングされていた値(あるいは値がないこと)が復活します。
変数は、同時に複数のローカルバインディングを持つことができます(例:その変数をバインドするletフォームが入れ子になっている場合など)。現在のバインディングとは、実際に有効となっているローカルバインディングのことです。これは、変数シンボルを評価した際に返される値を決定し、setqが作用するバインディングとなります。
ほとんどの場合、現在のバインディングは、最も内側のローカルバインディング、あるいはローカルバインディングが存在しない場合はグローバルバインディングであると考えて差し支えありません。より正確に言えば、スコープ規則と呼ばれるルールによって、プログラム内のどこでローカルバインディングが有効になるかが決まります。Emacs Lispにおけるデフォルトのスコープ規則は動的スコープと呼ばれ、これは単純に、プログラム実行中の任意の時点における現在のバインディングとは、その変数に対して最後に作成され、かつ現在も存在するバインディングのことである、というものです。動的スコープの詳細や、レキシカルスコープと呼ばれる別のスコープ規則については、変数バインディングのスコープ規則を参照してください。近年、Emacsではレキシカルバインディングをますます多くの箇所で採用する方向に進んでおり、最終的にはレキシカルバインディングをデフォルトにすることを目指しています。特に、すべてのEmacs Lispソースファイルと*scratch*バッファではレキシカルスコープが使用されています。
ローカルバインディングを作成するための特殊形式 let および let* があります:
この特殊形式は、bindingsで指定された特定の変数群に対してローカルバインディングを設定し、その後すべてのformsをテキスト順に評価します。その戻り値は、forms内の最後の形式の値となります。letによって設定されたローカルバインディングは、formsの本体内でのみ有効となります。
各 bindings は、(i) 記号(この場合、その記号は nil に局所的に束縛される)、または (ii) (symbol value-form)
形式のリスト(この場合、symbol は value-form の評価結果に局所的に束縛される)のいずれかである。value-form が省略された場合は、nil が使用される。
bindings 内のすべての value-form
は、シンボルをバインドする前に、出現順に評価されます。具体例を挙げると、z には y の新しい値である 1 ではなく、y の古い値である 2 がバインドされます。
(setq y 2)
⇒ 2
(let ((y 1)
(z y))
(list y z))
⇒ (1 2)
一方で、バインディングの順序は規定されていません。以下の例では、1 または 2 のいずれかが出力される可能性があります。
(let ((x 1)
(x 2))
(print x))
したがって、単一の let フォーム内で変数を複数回バインドしないようにしてください。
この特殊な形式は let
に似ていますが、各変数のローカル値を計算した直後にその変数を束縛し、次の変数のローカル値を計算する前に次の変数を束縛します。したがって、bindings 内の式は、この let*
形式で束縛された直前のシンボルを参照できます。以下の例を、前述の let の例と比較してください。
(setq y 2)
⇒ 2
(let* ((y 1)
(z y)) ; Use the just-established value of y.
(list y z))
⇒ (1 1)
基本的に、前述の例における x と y の
let* バインディングは、let
バインディングをネストして使用するのと同等です:
(let ((y 1))
(let ((z y))
(list y z)))
この特殊な形式は let*
に似ていますが、ローカル値のいずれかが計算される前に、すべての変数がバインドされます。その後、値がローカルにバインドされた変数に代入されます。これは、字句束縛が有効であり、let* を使用した場合にはまだ有効になっていないはずの束縛を参照するクロージャを作成したい場合にのみ有用です。
例えば、一度実行されるとフックから自身を削除するクロージャがこちらです:
(letrec ((hookfun (lambda ()
(message "Run once")
(remove-hook 'post-command-hook hookfun))))
(add-hook 'post-command-hook hookfun))
この特殊形式は let
に似ていますが、すべての変数を動的にバインドします。これが有用なケースは稀です。通常は、通常の変数は字句的に、特殊変数(すなわち defvar で定義された変数)は動的にバインドしたいものであり、let はまさにそれを実現するものです。
dlet
は、特定の変数が動的にバインドされていることを前提とした古いコードと連携する場合に有用ですが(動的バインドを参照)、これらの変数を defvar するのは現実的ではありません。dlet
は、バインドされた変数を一時的に特別な状態にしてフォームを実行し、その後、再び非特別な状態に戻します。
この特殊な形式は、Scheme言語に着想を得たループ構造です。letと同様に、bindings内の変数をバインドし、その後bodyを評価します。ただし、named-letはnameを、仮引数がbindings内の変数であり、本体がbodyであるローカル関数にもバインドします。これにより、bodyはnameを呼び出すことで自身を再帰的に呼び出すことができ、その際nameに渡される引数が、再帰呼び出しにおけるバインド済み変数の新しい値として用いられます。
数値のリストを合計するループの例:
(named-let sum ((numbers '(1 2 3 4))
(running-sum 0))
(if numbers
(sum (cdr numbers) (+ running-sum (car numbers)))
running-sum))
⇒ 10
body の 末尾位置 で発生する name への再帰呼び出しは、末尾呼び出し として最適化されることが保証されており、これは再帰がどれほど深く進んでも、追加のスタック領域を消費しないことを意味します。このような再帰呼び出しは、変数に新しい値を代入した状態で、実質的にループの先頭へとジャンプすることになります。
関数呼び出しが末尾位置にあるとは、それが最後に行われる処理であり、呼び出しによって返される値が body
自体の値となることを指します。これは、前述の sum への再帰呼び出しの場合に当てはまります。
named-let は、レキシカルバインディングが有効な場合にのみ使用できます。レキシカルバインディングを参照してください。
ローカルバインディングを生成するその他の機能の一覧は以下の通りです。
変数にはバッファローカルな束縛を持たせることもできます(バッファローカル変数を参照)。また、一部の変数にはターミナルローカルな束縛があります(複数ターミナルを参照)。こうした束縛は通常のローカル束縛とある程度同様に動作しますが、Emacs内の位置に応じて局所化されます。