検索エンジンから来た人に注意このマニュアルは、Emacs ver. 19.x 向けのマニュアルを Mule 2.x の開発にあたり邦訳したものを、 電脳外道学会がミラーリングしているものであり、旧版製品パラノイアであるところの椅子人の趣味によるものです。しかしながら、現在の Emacs の主流は ver. 20 以降であり、ver 19.x と ver 20.x とでは、仕様の違いが少なからずあります。 したがって、一般的な Emacs ユーザーにとっては、
このマニュアルと実機の動作とが符合しない場合があります。
|
変数(variable)とはプログラム内で使用される名前で、ある値を表します。ほ とんどすべてのプログラミング言語にはこのような変数があります。Lispプログラム のテキストでは、変数はシンボルの構文で記述します。
通常のプログラミング言語と異なり、Lispのプログラムは主にLispオブジェクトとし て表され、テキストとしては二次的にしか表されません。変数に使用されるLispオブ ジェクトはシンボルです。シンボル名が変数名で、変数の値はシンボルの値セルに 格納されます。シンボルは、変数として使うこととと関数名として使うこととは独立です。 See section シンボルの要素。
Lispプログラムを構成するLispオブジェクトは、そのプログラムのテキスト形式を決 定します。単に、そのLispオブジェクトのリード構文であるということです。このた め、たとえばテキストによるLispプログラムの変数の記述には、その変数を表すシンボル のリード構文を使用します。
変数のもっとも簡単な使用方法はグローバルに(globally)使うことです。すな わち変数の値は一度に一つだけで、この値は(少なくともこの時点では)Lispシステム 全域に対して有効であるということです。値は、新しく指定するまで有効です。値が 指定されて元の値が置き換えられた場合、元の値に対する痕跡は変数内に存在しなく なります。
シンボルに対する値はsetq
を用いて指定します。例を示します。
(setq x '(a b))
上の例では、変数x
に値(a b)
が指定されます。setq
は
最初の引数(変数名)は評価しませんが、二番目の引数(新規の値)は評価します。
変数がいったん値を持つと、シンボルそれ自体を式として用いた参照が行なえます。 すなわち、
x => (a b)
ここでは、上述したようなsetq
形式がすでに実行されたことを前提として
います。
再度setq
を行なうと、元の値が新しい値に置き換わります。
x => (a b) (setq x 4) => 4 x => 4
Emacs Lispには、nil
およびt
という特別なシンボルがあり、この二つの評
価結果は常に自分自身になります。これらのシンボルは、再束縛したり値セルを変更した
りすることはできません。nil
やt
を変更しようとすると、
setting-constant
エラーが発生します。
nil == 'nil => nil (setq nil 500) error--> Attempt to set constant symbol: nil
グローバル変数の値は、明示的に書き換えるまで保持されます。ただし、一時的にし か存在しない、すなわちプログラムの中で局所的(ローカル)にしか存在しない変数の値を作成し た方が便利な場合もあります。このような値はローカルである(local)といい 、その場合に使用する変数をローカル変数(local variables)といいます。
たとえば、関数が呼出された場合、仮引数はローカルな値を新しく受け取り、
関数を抜けるまで保持します。let
特殊形式は、指定された変数に対し新
規のローカルな値を明示的に確立します。これらの値はlet
形式から抜ける
まで存在しています。
ローカルな値を確立すると、その変数の直前の値(または値が存在しないという情報) が保存されます。ローカルな値のライフタイムが終わると、直前の値が復元されます 。その間、直前の値は隠されて(shadowed)おり、不可視(not visible) になっていたということができます。グローバル変数とローカル変数はどちらも隠し ておくことができます (see section スコープ)。
変数がローカルであるときにセットすると(setq
などを用いて)、ローカルの
値が置き換わります。グローバルの値や、隠されているローカル値の直前の値は変更
されません。この動作を示すために、局所的な束縛(local binding)について
、ローカル値と同じように説明しましょう。
局所的な束縛とは、局所的な値を保持している概念的な場所です。関数や、let
のような特殊形式を開始すると、局所的な束縛が作成されます。関数を抜けると、
let
は局所的な束縛を解除します。局所的な束縛が続いている間、変数の値は
その中に格納されています。局所的な束縛があるときに setq
やset
を
使用すると、その局所的な束縛には別の値が格納されます。新規に束縛が作成される
わけではありません。
グローバル束縛(global binding) についても述べておきましょう。ここには、 (概念的に) グローバル変数が保持されます。
変数には、局所的な束縛を同時に複数持たせることもできます(たとえば、ネストした
let
形式が束縛しているような場合)。このような場合、存在している最新の
局所的な束縛が、その変数の現在の束縛(current binding)になります。これを
動的スコーピング(dynamic scoping)といいます。section 変数束縛のスコーピングに関する規則を参照してく
ださい。局所的な束縛がない場合、その変数のグローバル束縛が現在の束縛になりま
す。また、現在の束縛のことを
既存の最も局所的な束縛(most-local existing binding)と呼んで強調するこ
ともあります。シンボルを通常に評価すると、かならずその現在の束縛の値を返します。
特殊形式 let
および let*
は、局所的な束縛を作成するためのものです。
let
-形式はformsにある末尾の形式の
値を返します。
bindings はそれぞれ、(i)シンボルまたは(ii)形式のリスト
(symbol value-form)
になります。前者の場合シンボルはnil
に束縛され、後者の場合symbolはvalue-formの評価結果に束縛され
ます。
value-formが省略された場合はnil
が使用されます。
bindingsのvalue-formはすべて現れた順に、どのシンボルが束縛されるよ
り前に評価されます。例を示します。Z
はY
の元の値、つ
まり新規の値1ではなく2に束縛されます。
(setq Y 2) => 2 (let ((Y 1) (Z Y)) (list Y Z)) => (1 2)
let
のようなものですが、この場合、束縛するのはローカル
値を計算した直後で、次の変数のローカル値を計算する前になります。そのため、
bindingsの式は、このlet*
形式で先行するシンボルを適切に参照できるよ
うになります。下に示す例を、上のlet
の例と比べてみてください。
(setq Y 2)
=> 2
(let* ((Y 1)
(Z Y)) ; Y
の確立されたばかりの値を使う
(list Y Z))
=> (1 1)
その他、局所的な束縛を作成する機能をすべて下に示します。
変数ではバッファローカルな束縛を持つことも可能です (see section バッファローカルな変数)。端末ローカルな束縛を持つ変数もわずかですがあ ります(see section 複数のディスプレイ)。このような種類の束縛処理は、通常の局所的な 束縛と多少類似していますが、それは、ローカライズした時点ではなく、Emacsの「どこ に」いるかということに依存します。
この変数は、ローカル変数束縛とunwind-protect
のクリーンアップの総数の
上限を定義します(see section 非局所脱出)。これらは、エラーが通知されるまで
(データ"Variable binding depth exceeds max-specpdl-size"
による)行なわ
れます。
この制限を超えると、それに対応するエラーが発生します。これは、適切に定義され ていない関数への無限再帰を防ぐためのものです。
デフォルトの値は 600 です。
max-lisp-eval-depth
はネスティングに対する別の制限です。
See section Eval。
シンボルにグローバル変数としての値をまったく指定していない場合、そのシンボルの
グローバル値はvoidであるといいます。つまり、そのシンボルのセルの中にはLisp
オブジェクトがないということです。そのシンボルを評価しようとすると、値を取得する
ことはできず、void-variable
エラーが発生します。
nil
はvoidとは別であることに注意してください。シンボルnil
はLisp
オブジェクトで、ほかのオブジェクトと同じように変数の値にすることもできます。た
だしこれは値です。void変数には値はありません。
変数に値を代入した後で、makunbound
を使用すると、変数は再度voidになります。
void-variable
エラーに
なります。
makunbound
はsymbolを返します。
(makunbound 'x) ; x
のグローバル
; 値をvoidにする。
=> x
x
error--> Symbol's value as variable is void: x
symbolが局所的に束縛されている場合、makunbound
は最も局所的な
束縛に作用します。シンボルの局所的な束縛をvoidにする方法はこれだけです。局所的
な束縛を作成する構文要素は、値とともに作成するためです。この場合、voidであ
るという状態は、長くても束縛と同じ期間しか継続しません。構文要素を抜けるな
どで束縛が削除された場合、直前の束縛またはグローバルな束縛が通常どおり再度現
れ、新規に現れた束縛がvoidである場合を除き、変数はvoidではなくなります。
(setq x 1) ; グローバル束縛に値を設定
=> 1
(let ((x 2)) ; 局所的に束縛
(makunbound 'x) ; 局所的な束縛をvoidにする
x)
error--> Symbol's value as variable is void: x
x ; グローバル束縛は変更されていない
=> 1
(let ((x 2)) ; 局所的に束縛
(let ((x 3)) ; くり返し
(makunbound 'x) ; もっとも内側の局所的な束縛をvoidにする
x)) ; 参照: void
error--> Symbol's value as variable is void: x
(let ((x 2))
(let ((x 3))
(makunbound 'x)) ; 内側の束縛をvoidにしてから削除
x) ; 外側のlet
束縛が可視になる
=> 2
makunbound
を用いてvoidにされた変数と、値が与えられなかったためにvoid
だった変数は、区別できません。
boundp
関数を使うと、変数が現在voidかどうかが調べられます。
boundp
は、variable(シンボル)がvoidでない場合(正確には、変数の
現在の束縛がvoidでない場合)はt
を返します。voidである場合は、
nil
を返します。
(boundp 'abracadabra) ; voidから開始 => nil (let ((abracadabra 5)) ; 局所的に束縛 (boundp 'abracadabra)) => t (boundp 'abracadabra) ; グローバルではvoidのまま => nil (setq abracadabra 5) ; グローバルでも非voidにする => 5 (boundp 'abracadabra) => t
シンボルをグローバル変数として使用するということは、変数定義(variable
definition)によってアナウンスできます。これは特殊形式で、defconst
また
はdefvar
のいずれかになります。
Emacs Lispでは、定義により3種類の目的が達成できます。まず、コードを読む人
間に対して、特定のシンボルが特定の方法で(変数として)使用されることを意図
されているということが伝わります。二番目に、このような情報がLispシステムに
も伝わり、値や説明が与えられます。三番目に、etags
やmake-docfile
など、プログラム内の関数や変数のデータベースを作成するユーティリティにも情報
が伝わります。
defconst
とdefvar
の主な違いは、プログラムが変数を変更するかどう
かを人間の読者に対して伝えるという意図にあります。Emacs Lispは、変数を使用す
る方法に関して、defconst
で宣言したかdefvar
で宣言したかという点
を区別しません。ただし、初期化には違いがあります。defconst
は無条件で
変数を初期化しますが、defvar
はvoidの場合にかぎり初期化を行ないます。
「ユーザ・オプションの変数は、プログラムによって値が変更されることがないので、
defconst
で定義する方がいい」と思われることもありますが、プリロードされ
ないライブラリで定義されている場合は、悪い結果を生じるでしょう。ライブラリが
ロードされる際、defconst
は前の値より優先します。ユーザの初期化ファイル
を使用してユーザ・オプションをセットし、定義に対するデフォルト値を書き換えるこ
ともできます。このため、ユーザ・オプションはdefvar
で定義する必要があり
ます。
defvar
に明示されている必要があります。
symbolに値がすでにある場合(すなわち、voidではない場合)、valueは
評価されず、symbolの値は変更されません。symbolがvoidでvalue
が指定されている場合、defvar
は評価を行ない、結果にsymbolをセット
します。(valueを省略すると、symbolの値が変更されることはありません。)
Emacs LispモードでC-M-xを用いてトップレベルのdefvar
形式を評価す
る(eval-defun
)と、eval-defun
の特殊機能によりdefconst
と
評価されます。この動作の目的は、個別の指示があった場合に、変数の値の再初期化
を確実に行なうということです。
symbolのカレント・バッファに、バッファローカルな束縛があれば、
defvar
はローカルな値ではなくデフォルトの値をセットします。
See section バッファローカルな変数。
doc-string引数があれば、これが変数の説明を指定します。(文書化を指定
できるということが、変数定義の主な利点のひとつです。)文書はシンボルの
variable-documentation
属性に格納されます。Emacsのヘルプ機能
(see section ヘルプ)はこの属性を検索します。
doc-stringの最初の文字が`*'の場合、この変数はユーザ・オプションで
あると考えられます。これにより、ユーザがset-variable
および
edit-options
で変数を簡単にセットすることができます。
たとえば、この形式はfoo
を定義しますが、その値は定義しません。
(defvar foo) => foo
次の例では、bar
の値を23
にセットし、説明文字列も
指定します。
(defvar bar 23 "The normal weight of a bar.") => bar
次の形式は、bar
の説明文字列を変更し、変数をユーザ・オプションにしますが、
値は変更しません。bar
にはすでに値があるためです。(追加されてい
る(1+23)
は実行されません。)
(defvar bar (1+ 23) "*The normal weight of a bar.") => bar bar => 23
defvar
特殊形式と等価である式の例を次に示します。
(defvar symbol value doc-string) == (progn (if (not (boundp 'symbol)) (setq symbol value)) (put 'symbol 'variable-documentation 'doc-string) 'symbol)
defvar
形式はsymbolを返しますが、通常はファイル中のトップレベルで
使用されるので、値は問題になりません。
defconst
に明示されている必要があります。
defconst
は、かならずvalueを評価して、その結果にグローバルな値
symbolをセットします。これにはvalueが指定されているということが条件
です。symbolに、バッファローカルな束縛がカレント・バッファにある場合、
defconst
はローカルな値ではなくデフォルトの値をセットします。
注意: 標準的なプリロードを行なっていないライブラリでは、
defconst
をユーザ・オプション変数に使用しないでください。このような変数
にはファイル`.emacs'でユーザによる値の指定ができるようにしておき、ライブ
ラリを後からロードしても効果があるようにしてください。
ここで、pi
はおそらく誰にも変更されない(インディアナ州議会はやろうとし
たが)定数です。ただし、二番目の形式でそれは単に勧告であるということを示してい
ます。
(defconst pi 3.1415 "Pi to five places.") => pi (setq pi 3) => pi pi => 3
variableがユーザ・オプション(ユーザによるカスタマイズのためのセットを意
図した変数)であれば、この関数はt
を返し、それ以外の場合はnil
を
返します。(ユーザ・オプション以外の変数も、Lispプログラム内で内部的に使用され
ており、ユーザはそれを知る必要はありません。)
ユーザ・オプション変数は、variable-documentation
属性の最初の文字によっ
て、ほかの変数から区別されています。`*'で始まる文字列の属性があれば、その
変数はユーザ・オプションです。
ユーザ・オプションの変数にvariable-interactive
属性があれば、
set-variable
コマンドはその値を使用して、変数に対する新しい値の読込み
を制御します。属性の値は、interactive
の場合と同じように使用されます。
警告!: 変数に局所的な束縛がある場合に、特殊形式defconst
およ
びdefvar
を使用すると、局所的な束縛の値がセットされます。グローバルな束
縛は変更されません。これは本来意図したところではないので、これを防ぐために、
このような特殊形式はファイルのトップレベルで使用してください。ここでは、通常
局所的な束縛は有効ではないからです。また、かならずファイルをロードしてから
変数に対する局所的な束縛を作成するようにしてください。
変数を参照する場合、最も一般的な方法は、その変数を特定するシンボルを書くことです
(see section シンボル形式)。この場合、プログラムを記述する際に変数名を指定する必
要があります。これが通常のやり方でしょう。ただし、どの変数を参照するかを実行
中に選択しなければならないこともあります。これには、symbol-value
を使用
します。
(setq abracadabra 5) => 5 (setq foo 9) => 9 ;; ここでは、シンボルabracadabra
;; の値が調べられる。 (let ((abracadabra 'foo)) (symbol-value 'abracadabra)) => foo ;; ここでは、abracadabra
;; すなわちfoo
の ;; 値が調べられる (let ((abracadabra 'foo)) (symbol-value abracadabra)) => 9 (symbol-value 'abracadabra) => 5
エラーvoid-variable
は、symbolに局所的な束縛もグローバルな値も
ないということを示します。
変数の値を変更する場合、通常は特殊形式setq
を使用します。実行時に変数の
選択を計算する必要がある場合は、関数set
を使用します。
setq
はsymbolを評価せず、記述したシンボルをセットします。この引数は
自動的にquote(automatically quoted)されます。 `q'は「quoted」の略
です。
setq
形式の値は、最後にあるformの値になります。
(setq x (1+ 2)) => 3 x ;x
がグローバルな値を取得 => 3 (let ((x 5)) (setq x 6) ;x
の局所的な束縛をセット x) => 6 x ; グローバルな値は変更されない => 3
最初のformが評価され、それから最初のsymbolがセットされ、次に二番目の formが評価され、二番目のsymbolがセットされるという順序で実行されるこ とに注意してください。
(setq x 10 ;x
はy
の値を計算する前に y (1+ x)) ; セットされているということに注意 => 11
set
は関数なので、symbolに対して記述した式が評価されて、セットする
シンボルを取得します。
変数の既存の束縛で最も局所的な束縛がセットされます。隠されている束縛は影響さ れません。
(set one 1) error--> Symbol's value as variable is void: one (set 'one 1) => 1 (set 'two 'one) => one (set two 2) ;two
はシンボルone
に評価される => 2 one ; したがって、one
がセットされる => 2 (let ((one 1)) ;one
のこの束縛をセット (set 'one 3) ; グローバルな値ではない one) => 3 one => 2
symbolが実際のシンボルではない場合、wrong-type-argument
エラーが発生します。
(set '(x y) 'z) error--> Wrong type argument: symbolp, (x y)
論理的にいうと、set
はsetq
よりもプリミティブなものです。
setq
を使っている箇所はすべて、set
を使うように書き換えることが簡
単にできます。 set
が使える場合は、setq
をマクロで定義することも
できます。ただし、set
自身が使用されることはほとんどなく、初心者が知る
必要はないでしょう。この操作が便利になるのは、実行時にどの変数をセットするかを
選択するような場合に限られます。たとえば、set-variable
コマンドはユーザ
から変数名を読込んで変数をセットするので、set
を使用する必要があります。
Common Lisp注意書き: Common Lispでは、
set
はかならずシンボルの特殊な値を変更し、 辞書的な束縛をすべて無視します。Emacs Lispでは、変数と束縛はすべて(実質上)特 殊なので、set
は常に、最も局所的な束縛に影響を与えます。
変数をセットする別の関数には、リストに入っていない要素をリストに追加するように 設計されているものがあります。
symbolを引用符で囲むということは含意されていません。add-to-list
はset
と同じような通常の関数で、setq
とは異なっています。必要
に応じて、引数を引用符で囲んでください。
add-to-list
の使用例を示します。
(setq foo '(a b)) => (a b) (add-to-list 'foo 'c) ;;c
を追加 => (c a b) (add-to-list 'foo 'b) ;; 効果なし => (c a b) foo ;;foo
を変更 => (c a b)
(add-to-list 'var value)
は、次のような式に相当
します。
(or (member value var) (setq var (cons value var)))
指定されたシンボルfoo
には、Lispプログラムの各所で確立されたいくつかのロー
カルな変数束縛と、グローバルな束縛が存在することがあります。最も新しく確立さ
れた束縛は、ほかのものより優先されます。
Emacs Lispの局所的な束縛には無限スコープ(indefinite scope)と 動的エクステント(dynamic extent)があります。 スコープ(Scope)とは、束縛が ソースコードの本文中のどの部分にアクセスできるかということを表していま す。無限スコープとは、変数の束縛がプログラムのどの部分にもアクセスできる可能性が あるということです。エクステント(Extent)は、プログラムの実行中、 どの時点で束縛が存在するかということを表します。動的エクステントとは、その 束縛を確立した構文要素がアクティブである間は、かならず束縛が継続して存在する ということを表します。
動的エクステントと無限スコープを組み合わせを動的スコーピング(dynamic scoping)といいま す。それに対して、ほとんどのプログラミング言語では、 辞書的スコーピング(lexical scoping)を用いています。この場合、ローカル変数への参 照は、関数の内部か、またはその変数を束縛するブロックの内部に存在している必要 があります。
Common Lispに関する注意: Common Lispで"special"として宣言された変数は、 Emacs Lispの変数と同じようにスコープは動的になります。
Emacs Lispは、ローカルな変数束縛に無限スコープ(indefinite scope)を使用しま す。これは、プログラムのテキスト内にある関数はすべて、指定された変数束縛への アクセスが可能であることを表します。次のような関数定義を考えてみてください。
(defun binder (x) ;x
はbinder
で束縛される (foo 5)) ;foo
はほかの関数 (defun user () ;x
はuser
で使用される (list x))
辞書的にスコープしている言語では、binder
の中のx
に
user
でアクセスすることはできません。user
が関数binder
に含まれていないためです。ただし、動的スコープのEmacs Lispでは、user
は、
binder
で確立されるx
の束縛を参照する場合と参照しない場合(状
況による)があります。
binder
をまったく呼出さずにuser
を直接呼出すと、x
の束縛があっても、それはbinder
からきたものではありません。
foo
を以下のように定義してbinder
を呼出すと、binder
で作成された束縛は、user
で可視になります。
(defun foo (lose) (user))
foo
を以下のように定義してbinder
を呼出すと、binder
で作成された束縛は、user
で不可視になります。
(defun foo (x) (user))ここで、
foo
がbinder
から呼出されると、x
が束縛されます。
(foo
で束縛を行なうことはbinder
で作成されたものを
隠す(shadow)といいます。)したがって、user
は、binder
ではなく
foo
で束縛されたx
にアクセスできるようになります。
エクステント(extent)とは、プログラムを実行する際に変数名が有効である時間 を表します。 Emacs Lispでは、変数が有効になるのは、その変数を束縛する形式の実 行中に限られます。これを、動的エクステント(dynamic extent)といいます。Cや Pascalなど、ほとんどの言語では「ローカル」または「自動」変数に動的エクステントが あります。
別の動的エクステントに無限エクステント(indefinite extent)があります。これは、変 数の束縛が、その束縛を作成した形式から抜けた後も存続するという意味です。たと えば、Common Lisp やSchemeではこれをサポートしていますが、Emacs Lispではサポー トしていません。
これを図示すると、以下の関数でmake-add
は、独自の引数mに
nを追加する関数を返します。これはCommon Lispでは動作しますが、Emacs
Lispを意図した場合には動作しません。make-add
への呼出しを抜けた
後、変数n
は実引数2には束縛されていないためです。
(defun make-add (n) (function (lambda (m) (+ n m)))) ; 関数を返す => make-add (fset 'add2 (make-add 2)) ;(make-add 2)
で ; 関数add2
を定義 => (lambda (m) (+ n m)) (add2 4) ; 2と4を加算 error--> Symbol's value as variable is void: n
Lispの方言には"closure"を持つものがあります。これは関数と同じようなオブ ジェクトですが、変数束縛も記録できます。Emacs Lispにはclosureはありま せん。
簡単な実装例(Emacs Lispの実際の動作というわけではありません)により、動的束縛 が理解しやすくなるでしょう。この手法は深い束縛(deep binding)と呼ばれて おり、初期の Lispシステムで使用されていました。
束縛のスタック(変数と値の対)があるとします。関数またはlet
形式の開
始地点で、引数またはそこで作成されるローカル変数に対して束縛をスタックにプッ
シュします。束縛構造を抜けた時点で、スタックから束縛をポップすることができます。
変数の値を検索する場合は、スタックを先頭から末尾まで調べて、その値に対する束 縛を検索します。その束縛からの値は変数の値です。変数をセットするには、まず現在の 束縛を検索し、新規の値をその束縛に格納します。
みればわかるはずですが、関数の束縛は実行中であればかならず有効になっています。 これは、ほかの関数を呼出している場合でも変わりません。束縛のエクステントが動的 であるというのは、このためです。ほかの関数からでも、その束縛が有効である時点で 同じ変数を使用すると、この束縛を参照できます。スコープが無限であるというのは、こ のためです。
変数スコーピングを実装する場合、GNU Emacs Lispでは浅い束縛(shallow binding)とい う手法を使用します。各変数には標準的な位置があり、現在の値はすべてその場所に あります。すなわち、シンボルの値セルです。
浅い束縛では、変数のセットは、値を値セルに格納することで行ないます。新規の束縛は、 従来の値(直前の束縛に属する)をスタックにプッシュし、ローカルな値を値セルに 格納することで作成されます。束縛の除去は、従来の値をスタックから値セルにポッ プすることで行ないます。
浅い束縛を使用する理由は、深い束縛と同じ結果が得られて高速に実行できるためで す。これは、束縛を検索する必要がないためです。
ある関数で変数を束縛してほかの関数で使用することは、高度な手法ですが、乱用する とプログラムが判読しにくくなります。この手法をわかりやすく使用する方法は二とおり あります。
case-fold-search
を「非nil
の場合、検索時に大文字/小文字を区別し
ない」と定義するとします。検索・置換の関数はすべて直接またはサブルーチンを介
してその変数を参照しますが、束縛やセットは行ないません。
これで、その変数の効果が確実にわかり、ほかのプログラムでその変数が束縛できるよ
うになります。
どちらの場合でも、変数はdefvar
で定義してください。これにより、ほかのプ
ログラマたちも、関数間の使用方法をみればプログラムがわかるようになります。ま
た、バイトコンパイラからの警告も避けられます。変数名が重複しないように注意し
てください---x
などの短い名称は避けてください。
グローバル変数とローカル変数の束縛は、ほとんどのプログラミング言語でさまざま な形式で行なわれています。Emacsもあまり一般的でない種類の変数束縛をサポートして います。これはバッファローカル(buffer-local)な束縛といい、適用される バッファはひとつに限定されます。Emacs Lispは編集コマンドをプログラムするため のものであり、別々のバッファに別々の値が入るということが、カスタマイズの重要 な方法なのです。 (指定されたX端末に対して局所的な束縛を持つ変数も多少あります。 section 複数のディスプレイを参照してください。)
バッファローカルな変数には、バッファローカルな束縛があり、特定のバッファ に対応しています。束縛は、そのバッファがカレント・バッファであれば有効です。 カレント・バッファでなければ有効ではありません。バッファローカルな束縛が有 効な時点で変数をセットすると、新規の値はその束縛にはいるので、グローバルな束 縛は変更されません。すなわち、変更がわかるのはそのバッファのみになるというこ とです。
変数には、バッファローカルな束縛が一部のバッファにしかないというものがあり
ます。グローバルな束縛は、独自の束縛を持たないバッファすべてに共有されます。
したがって、バッファローカルな束縛を持たないバッファにある変数をセットすると、
新規の値は、バッファローカルな束縛を持たないバッファすべてで可視になります。
(ここでは、問題を複雑にするlet
形式の局所的な束縛がないことを前提にして
います。)
バッファローカルな束縛を使用する場合、もっとも一般的なものは主モードのもの
で、コマンドの動作を制御する変数を変更するという方法です。たとえば、Cモードと
Lispモードは、どちらも変数paragraph-start
をセットすることにより、空行の
みがパラグラフを分割するという指定を行ないます。これは、CモードやLispモードに
なったバッファローカルな変数を作成し、そのモードに対する新規の値をセットする
ことで行ないます。
バッファローカルな束縛は、通常、主モード・コマンドが使用する
make-local-variable
で作成します。これはカレント・バッファのみに影響し
ます。ほかのバッファ(まだ作成されていないものも含む)はグローバルな値の共有を継
続します。
さらに高度な操作として、make-variable-buffer-local
を呼出して変数を
automatically buffer-localと印づけるという方法があります。これは、す
べてのバッファで変数をローカルにすると考えることができます。さらに正確にいう
と、この効果は、変数をセットした場合、その変数がカレント・バッファに対してバッ
ファローカルでなければ、自動的にバッファローカルになるということです。す
べてのバッファは、最初は変数のグローバルな値を共有しますが、setq
があれ
ば、カレント・バッファに対するバッファローカルな束縛を作成します。新規の値
はバッファローカルな束縛を格納し、(デフォルトの)グローバルな束縛は変更され
ません。グローバルな値はsetq
で変更されることがなくなるので、変更には
setq-default
を使用する必要があります。
警告!: 変数が一つまたは複数のバッファにローカル変数を持っていた場合、
変数をlet
に束縛し、ほかの束縛が有効であるほかのカレント・バッファに変更し
てlet
を抜けると、Emacsはひじょうに混乱します。これにより、グローバル束
縛および局所的な束縛の値がごちゃまぜになります。
正常を保つためには、このような一連の動作を避けるようにしてください。カレント
・バッファを変更する各コードの周囲でsave-excursion
を使用すると、このよ
うな問題が発生します。何を避けるかという例をここに示します。
(setq foo 'b) (set-buffer "a") (make-local-variable 'foo) (setq foo 'a) (let ((foo 'temp)) (set-buffer "b") body...) foo => 'a ; バッファ`a'に対する従来のローカルな値が ; デフォルト値になる (set-buffer "a") foo => 'temp ; 消去すべきローカルな値が ; バッファ`a'に対するローカルな値になる
ただし、ここで示すようにsave-excursion
が問題を回避します。
(let ((foo 'temp)) (save-excursion (set-buffer "b") body...))
body内のfoo
への参照が、バッファ`b'に対してバッファローカルな束
縛にアクセスするという点に注意してください。
ファイルがローカルな値を指定する場合、これらの値はファイルをvisitした時点でバッ ファローカルになります。 See section 主モードの自動選択の仕組み。
バッファローカルなvariableの値は、最初は、variableの直 前の値と同じになります。variableがvoidの場合はvoidのままです。
;; In buffer `b1': (setq foo 5) ; 全バッファに影響 => 5 (make-local-variable 'foo) ; `b1'内でローカルになる => foo foo ; 値を変更 => 5 ; しなかった (setq foo 6) ; `b1'の値を => 6 ; 変更 foo => 6 ;; バッファ`b2'では、値は変更されていません。 (save-excursion (set-buffer "b2") foo) => 5
バッファローカルな変数を作成する場合、その変数に対するlet
束縛
の内部で行なっても動作しません。これは、let
が異なる種類の束縛を区別しな
いためです。束縛がどの変数に対して作成されたかということのみを識別します。
変数が端末ローカルであれば、この関数はエラーを通知します。このような 変数には、バッファローカルな束縛も使用できません。 See section 複数のディスプレイ。
注意!: フック変数にはmake-local-variable
ではなく
make-local-hook
を使用してください。
See section フック。
戻り値はvariableです。
t
を返します。それ以外の場合は nil
を
返します。
(make-local-variable 'foobar) (makunbound 'foobar) (make-local-variable 'bind-me) (setq bind-me 69) (setq lcl (buffer-local-variables)) ;; 最初は、すべてのバッファでローカルな組込み変数 => ((mark-active . nil) (buffer-undo-list nil) (mode-name . "Fundamental") ... ;; 次に、非組込みのローカル変数 ;; これはローカルでvoidになっている foobar ;; これはローカルでvoidになっていない (bind-me . 69))
このリストにあるコンス・セルのCDRに新規の値を格納しても、変数のローカル な値は変更されないので注意してください。
セットされると自動的にローカルになる変数の局所的な束縛をkillすると、グローバ ルな値はカレント・バッファで可視になります。ただし、変数を再度セットすると、 局所的な束縛が再度作成されます。
kill-local-variable
はvariableを返します。
この関数はコマンドです。これは、バッファローカルな変数の対話的な作成が便利 であり、同様にバッファローカルな変数を対話的にkillすることも便利であるためです。
また、この関数はバッファに対するほかの特定情報のリセットも行ないます。これは、ロー
カルなキーマップをnil
に、構文テーブルをstandard-syntax-table
の
値に、略称テーブルをfundamental-mode-abbrev-table
の値にセットします。
主モードのコマンドはすべて、この関数の呼出しで開始されます。これには、 Fundamentalモードに切り替え、直前の主モードの効力をほとんど削除するという効力 があります。この作業を確実に行なうには、主モードがセットする変数に permanentの印 をつけないようにしてください。
kill-all-local-variables
はnil
を返します。
ローカル変数は、その変数名(シンボル)のpermanent-local
の属性が nil
で
ない場合にpermanentになります。常時ローカルな変数は、そのファイル
の内容の編集方法ではなく、ファイルの場所や保存方法に属しているデータに対して
適切なものになります。
バッファローカルな束縛のある変数のグローバルな値はデフォルト(default) 値ともいいます。この値は、明示して無視しないかぎり有効になるためです。
関数default-value
とsetq-default
は、変数のデフォルト値をアクセス
したり変更したりします。これには、カレント・バッファにバッファローカル
な束縛があるかどうかは無関係です。たとえば、setq-default
を用いて、ほと
んどのバッファに対するparagraph-start
のデフォルトセットを変更することが
できます。これは、CまたはLispモードのバッファにいて、この変数に対して
バッファローカルな値がある場合でも同様です。
また、特殊形式defvar
およびdefconst
は、ローカル値ではなくデフォ
ルト値(変数をセットすることがあれば)のセットも行ないます。
symbol-value
と等価になります
(see section 変数の値へのアクセス)。
default-boundp
は、symbolのデフォルト値がvoid以外である
かどうかを示します。(default-boundp 'foo)
がnil
を返す場合、
(default-value 'foo)
はエラーになります。
boundp
がsymbol-value
に対応することと同じように、
default-boundp
はdefault-value
に対応します。
setq-default
形式の値はvalueになります。
symbolがカレント・バッファに対してバッファローカルでなく、自動的にバッ
ファローカルになるという印もついていない場合、setq-default
の効果
は setq
と同じになります。symbolがカレント・バッファに対してバッ
ファローカルであれば、これにより、ほかのバッファの値は変更されますが(バッファ
ローカルな値を持たないバッファの場合)、カレント・バッファが認識する値は変更
されません。
;; バッファ`foo'で: (make-local-variable 'local) => local (setq local 'value-in-foo) => value-in-foo (setq-default local 'new-default) => new-default local => value-in-foo (default-value 'local) => new-default ;; `bar'バッファ(新規)で: local => new-default (default-value 'local) => new-default (setq local 'another-default) => another-default (default-value 'local) => another-default ;; `foo'バッファに戻る: local => value-in-foo (default-value 'local) => another-default
setq-default
と同じようなものですが、symbolが評価さ
れるという点が異なります。
(set-default (car '(a b c)) 23) => 23 (default-value 'a) => 23
Go to the first, previous, next, last section, table of contents.