Previous: Lexical Binding, Up: Variable Scoping [Contents][Index]
Emacs
LispファイルのロードやLispバッファーを評価するとき、バッファーローカルな変数lexical-binding
が非nil
なら、レキシカルバインディングが有効になります:
このバッファーローカルな変数が非nil
なら、Emacs
Lispファイルとバッファーはダイナミックバインディングではなくレキシカルバインディングを使用して評価される(しかし特別な変数はダイナミックにバインドされたまま。以下を照)。nil
ならすべてのローカル変数にたいしてダイナミックバインディングが使用される。この変数は、通常はファイルローカル変数として、Emacs
Lispファイル全体にたいしてセットされる(File Local Variablesを参照)。他のファイルローカル変数などとは異なり、ファイルの最初の行でセットされなければならないことに注意。
eval
呼び出しを使用してEmacs
Lispコードを直接評価するとき、eval
のlexical引数が非nil
なら、レキシカルバインディングが有効になります。Evalを参照してください。
レキシカルバインディングは*scratch*バッファーで使用されるLisp
Interactionモード、および*ielm*バッファーで使用されるIELMモードでも有効であり、M-:
(eval-expression
)を通じた式の評価や、Emacsとemacsclient
(emacsclient Options in The GNU Emacs
Manualを参照)の--evalコマンドラインオプション(Action Arguments in The
GNU Emacs Manualを参照)を処理する際にも有効です。
レキシカルバインディングが有効な場合でも、特定の変数はダイナミックにバインドされたままです。これらはスペシャル変数(special
variable)と呼ばれます。defvar
、defcustom
、defconst
で定義されたすべての変数はスペシャル変数です(Defining Variablesを参照)。その他のすべての変数はレキシカルバインディングの対象になります。
値なしでdefvar
を使用することにより、他の場所ではレキシカルにバインドされている状態のまま、単一ファイルやファイルの一部だけで変数をダイナミックにバインドすることが可能になります。たとえば:
(let (_) (defvar x) ;x
へのletバインドはこのlet内ではダイナミック (let ((x -99)) ; これはx
のダイナミックバインド (defun get-dynamic-x () x))) (let ((x 'lexical)) ; これはx
のレキシカルバインド (defun get-lexical-x () x)) (let (_) (defvar x) (let ((x 'dynamic)) (list (get-lexical-x) (get-dynamic-x)))) ⇒ (lexical dynamic)
この関数はsymbolがスペシャル変数(つまり変数がdefvar
、defcustom
、defconst
による定義をもつ)なら非nil
をリターンする。、それ以外ならリターン値はnil
。
これは関数なので永続的にスペシャルな変数には非nil
をリターンできるが、カレントレキシカルスコープでのみスペシャルな変数では異なることに注意。
関数内での通常の引数としてのスペシャル変数の使用は、推奨されません。レキシカルバインディングモードが有効なときにこれを行うと、(あるときはレキシカルバインディング、またあるときはダイナミックバインディングのような)不定な動作が起こります。
Emacs Lispプログラムをレキシカルバインディングに変換するのは簡単です。最初にEmacs
Lispソースファイルのヘッダー行でlexical-binding
をt
にして、ファイルローカル変数を追加します(File Local Variablesを参照)。次に意図せずレキシカルにバインドしてしまわないように、ダイナミックなバインドをもつ必要がある変数が変数定義をもつことを各変数ごとにチェックします。
どの変数が変数定義をもつ必要があるか見つけるシンプルな方法は、ソースファイルをバイトコンパイルすることです。Byte Compilationを参照してください。let
フォームの外側で非スペシャル変数が使用されていれば、バイトコンパイラーはフリーな変数にたいする参照や割り当てについて警告するでしょう。非スペシャル変数がバインドされているがlet
フォーム内で使用されていなければ、バイトコンパイラーは使用されないレキシカル変数に関して警告するでしょう。バイトコンパイラーは、スペシャル変数を関数の引数として使用している場合も問題を警告します。
(使用されていない変数についての警告を抑制するためには単に変数名をアンダースコアーで開始する。そうすればバイトコンパイラーは変数が使用されないことを示すと解釈する。)