検索エンジンから来た人に注意このマニュアルは、Emacs ver. 19.x 向けのマニュアルを Mule 2.x の開発にあたり邦訳したものを、 電脳外道学会がミラーリングしているものであり、旧版製品パラノイアであるところの椅子人の趣味によるものです。しかしながら、現在の Emacs の主流は ver. 20 以降であり、ver 19.x と ver 20.x とでは、仕様の違いが少なからずあります。 したがって、一般的な Emacs ユーザーにとっては、
このマニュアルと実機の動作とが符合しない場合があります。
|
シンボル(symbol)とは固有の名前をもつオブジェクトのことです。この 章では、シンボルとそれを構成する要素、その属性リストについてお話しし、 さらにそれらがどのようにして生成され、internされるかについて説明します。 シンボルを変数名や関数名として利用することについては、章を改めて記述し ますので、それらについてはsection 変数とsection 関数を参照してく ださい。シンボルの正確なリード構文については、section シンボル型を御覧く ださい。
任意のLispオブジェクトがシンボルであるかどうかは、symbolp
で調べ
ることができます:
t
を返し、そうでなければ
nil
を返します。
各シンボルは四つの要素("セル"ともいう)を持っており、それぞれはさら に別のオブジェクトを参照します:
symbol-name
を参照してください。
symbol-value
を参照してください。
symbol-function
を参照してください。
symbol-plist
を参照してください。
印字名セルは、常に文字列を格納し、これを変更することはできません。ほか の三つのセルには、与えられた任意のLispオブジェクトを個別にセットするこ とができます。
印字名セルは、そのシンボルの名前である文字列を保持しています。シンボル は、その名前によってテキスト的に表現されるため、同じ名前で二つのシンボ ルが存在しないことは重要です。これはLispリーダによって保証されます。と いうのは、シンボルを読み込むときには新しいシンボルを作成する前に、まず 指定された名前を持つ既存のシンボルがないかどうか検索するからです(GNU Emacs Lispでは、この検索にはハッシュ・アルゴリズムとobarrayを用います。 section シンボルの作成と internを参照してください)。
通常の使い方では、関数セルは、Lispインタプリタがそこに期待するとおりの
関数かマクロを保持します(see section 評価)。また、ときどきは、キーボー
ド・マクロ(see section キーボード・マクロ)、キーマップ(see section キーマップ)および
自動ロード・オブジェクト(see section 自動ロード)もシンボルの関数セルに格納
されることもあります。しばしば、"関数 foo
"という言い方をします
が、実際にはシンボルfoo
の関数セルに格納された関数を意味します。
これらは、必要なときにのみ使い分けられます。
属性リスト・セルは、通常正しい形式の属性リスト(see section 属性リスト) を保持すべきものであり、多くの関数はそこに属性リストがあるものとみなし ています。
関数セルや値セルは、void(無値)であるかも知れません。これは、そ
のセルが何のオブジェクトも参照していないことを示しています(これは、
void
というシンボルを保持していることとは違いますし、nil
と
いうシンボルを保持していることとも違います)。voidであるセルをいじると、
`Symbol's value as variable is void'というようなエラーになります。
symbol-name
、symbol-value
、symbol-plist
、
symbol-function
という四つの関数があり、これらは、シンボルの四つ
のセルの内容を返します。ここで、buffer-file-name
というシンボルの
四つのセルの内容を例として示しましょう:
(symbol-name 'buffer-file-name) => "buffer-file-name" (symbol-value 'buffer-file-name) => "/gnu/elisp/symbols.texi" (symbol-plist 'buffer-file-name) => (variable-documentation 29529) (symbol-function 'buffer-file-name) => #<subr buffer-file-name>
このシンボルは、カレント・バッファに対応づけられているファイルの名前を
保持する変数ですから、今その値セルの内容は、Emacs Lisp Manualのこの章の
ソース・ファイルの名前になっています。
(8)
属性リスト・セルは、buffer-file-name
という変数の説明文字列が
`DOC'ファイルのどこで見つかるかを説明関数に伝える
(variable-documentation 29529)
というリストを格納しています(29529
とは、説明文字列が始まる場所の、`DOC'ファイルの先頭からのオフセッ
ト値です)。関数セルは、このファイル名を返す関数を保持しています。
buffer-file-name
が指すのはプリミティブ関数であり、これはリード構
文を持たず、ハッシュ表記(see section プリミティブ関数型)で印字されます。
Lisp言語で記述された関数を指すシンボルの場合であれば、このセルはラムダ
式(あるいはバイトコード・オブジェクト)を持つはずです。
Lispにおいて、定義(definition)とは、あるシンボルを特定の用途で用 いることを告知するための特殊形式です。Emacs Lispでは、シンボルを変数と して定義したり、関数(またはマクロ)として定義したり、さらに両方を独立に 行なったりできます。
定義構文要素はふつう、シンボルのある一つの用法における値や意味と、それ に加えてその用法におけるその意味に関する説明文も与えます。つまり、ある シンボルを変数として定義した場合には、その変数の初期値と、それに加えて その変数の説明文を与えることができます。
defvar
とdefconst
は、シンボルをグローバル変数として定義す
る特殊形式です。それらはsection グローバル変数の定義に詳しく記述されていま
す。
defun
は、シンボルを関数として定義し、ラムダ式を作ってシンボルの
関数セルに格納します。したがってこのラムダ式がそのシンボルの関数定義と
なります("関数定義"という用語は、関数セルの内容ということを意味します
が、これはdefun
がシンボルに対して、関数としての定義を与えるので
あるという発想からきたものです)。defsubst
とdefalias
は、関
数を定義するほかの二とおりのやり方です。See section 関数。
defmacro
は、シンボルをマクロとして定義します。これはマクロ・オブ
ジェクトを作成し、それをシンボルの関数セルに格納します。ここで注意して
いただきたいのは、ある一つのシンボルはマクロまたは関数のどちらか一方に
はなることができますが、同時に両方にはなれません。というのも、マクロと
関数のいずれもが関数セルに保持され、またどの時点でもセルはただ一つの
Lispオブジェクトしか保持できないからです。See section マクロ。
Emacs Lispにおいて、変数や関数としてシンボルを利用するにあたって、定義
は必須のものではありません。このため、シンボルをグローバル変数とするこ
とはsetq
で可能で、これは始めに定義を行なうかどうかには関係しま
せん。定義の本当の目的は、プログラマとプログラミング・ツールをガイドす
ることです。定義を行なうことにより、コードを読むプログラマに、あるシン
ボルが変数とか関数として使われることを意図しているということを伝
えるわけです。さらに、`etags'や`make-docfile'のようなユーティ
リティは定義を認識し、適当な情報をタグ・テーブルや
`emacs/etc/DOC-version'ファイルに加えるわけです。
See section 説明文字列へのアクセス。
GNU Emacs Lispにおいてシンボルがどのように作成されるかを理解するには、 Lispがそれらをどう読み込むのかを理解しなければなりません。Lispは、同じ ひと揃いの文字を読み込んだときには、常に同じシンボルを見つけ出さなけれ ばなりません。これに失敗すると、まるっきりの混乱を招くはずです。
Lispリーダがシンボルに出会うと、名前のすべての文字を読み込みます。次に それらの文字に対する"ハッシュ"が行なわれ、obarrayと呼ばれる表に 対するインデクスを見つけます。ハッシュというのは何かを検索するのに効率 的な手法です。たとえば電話帳でJan Jonesさんを探すときには、端から探して ゆく代りにまずJのところを始点にしてそこから探し始めます。これは単純な形 のハッシュ法です。obarrayの各要素はバケツ(bucket)であり、それはあ るハッシュ・コードに対するすべてのシンボルを保持しています。与えられた 名前を探すには、その名前のハッシュ・コードに対応するバケツに入っている すべてのシンボルを調べれば充分なのです。
所望の名前をもつシンボルが見つかると、リーダはそのシンボルを使います。 obarrayにその名前をもつシンボルが含まれていなければ、リーダは新たにシン ボルを作り、obarrayにそれを追加します。ある名前をもつシンボルを検索また は追加することを、internする(interning)といい、またそのシンボルは internされたシンボル(interned symbol)と呼ばれます。
internを行なうことで、それぞれのobarrayが、どんな特定の名前に対してもた だ一つのシンボルを持つことが保証されます。同じ名前のほかのシンボルも存 在しえますが、同じobarrayの中には存在しません。そのため、同じobarrayを 使って読込みを続けるかぎり、リーダは同じ名前に対しては同じシンボルを 得るのです。
すべてのシンボルを保持するobarrayは存在しません。それどころか、どの obarrayにも属さないシンボルもあります。それらは、internされていな いシンボル(uninterned symbols)と呼ばれます。internされていないシンボル でも、ほかのシンボル同様に四つのセルを持っています。しかし、それにアクセ スする唯一の方法は、ほかのオブジェクトの中から見つけるか、変数の値とし て探しだすかの方法しかありません。
Emacs Lispでは、obarrayは実はベクタです。ベクタの各要素はバケツであり、
その値は、名前がそのバケツにハッシュされるようなシンボルであるか、ある
いはバケツが空ならば0になります。internされたシンボルはそれぞれバケツ内
での次のシンボルへの(ユーザには見えない)内部リンクを持ちます。これらの
リンクが見えないため、あるobarray内のシンボルをすべて探し出すことは、
mapatoms
(後述)を使う以外にはできません。バケツ内でのシンボルの
順序には意味はありません。
空のobarrayでは、どの要素も0であり、obarrayを(make-vector
length 0)
で作成することができます。これがobarrayを作成す
る唯一の正当な方法です。 素数をlengthに使うと、よいハッシングになる傾
向があります。また、2のべき乗から1を引いた値もlengthとして適しています。
obarrayにシンボルを勝手に入れようとしてはいけません。これは動
作しません。intern
だけがobarryにシンボルを正しく入れることができ
ます。一つのシンボルを二つのobarryにinternしてはなりません。こ
れをやると両方のobarrayをグシャグシャにしてしまいます。というのも、シン
ボルはobarryバケツの中での次のシンボルを入れておくスロットを一つしか持
たないためです。このようなことを行なったときの結果は予測できません。
二つの異なるシンボルが、別のobarray内で同じ名前をもつこともあり得ます。
その場合、これらのシンボルはeq
でもequal
でもありません。し
かし、こうしたことはふつう省略形(abbrev)のメカニズム(see section 省略形とその展開)の
一部として起こるだけです。
Common Lisp注意書き:Common Lispの場合、一つのシンボルが複数の obarray相当にinternされ得ます。
以下の関数の大部分は引数として名前を取り、場合によってはそれに加えて
obarrayを取ることもあります。名前が文字列でないか、またはobarrayがベク
タでないと、wrong-type-argument
エラーが通知されます。
(symbol-name 'foo) => "foo"
文字を入れ換えてこの文字列を変更するとか、いろいろやればシンボルの名前 を変えることになりますが、 obarrayを更新できませんから、これはやらない でください。
nil
です。以下の例において、
sym
の値はfoo
とeq
にはなりません。というのも、それは
同じく`foo'という名前をもつ、internされていない別のシンボルになる
ためです。
(setq sym (make-symbol "foo")) => foo (eq sym 'foo) => nil
intern
は新
しくそれを作り、それをそのobarrayに加えたうえで返します。obarray
が省略された場合には、グローバル変数obarray
の値が用いられます。
(setq sym (intern "foo")) => foo (eq sym 'foo) => t (setq sym1 (intern "foo" other-obarray)) => foo (eq sym 'foo) => nil
nil
を返します。したがって、intern-soft
を、与えられた名前をもつシン
ボルがすでにinternされているかどうかを調べるために用いることができます。
obarrayが省略された場合には、グローバル変数obarray
の値が用
いられます。
(intern-soft "frazzle") ; そのようなシンボルは存在しない。 => nil (make-symbol "frazzle") ; internされていないものを作る。 => frazzle (intern-soft "frazzle") ; これは見つけ出せない。 => nil (setq sym (intern "frazzle")) ; internされたものを作る。 => frazzle (intern-soft "frazzle") ; これは見つけ出せる! => frazzle (eq sym 'frazzle) ; で、同じものになる。 => t
intern
とread
で用いられる標準のobarrayです。
nil
です。obarrayが省
略されると、デフォルト値として普通のシンボル用の標準のobarrayである
obarray
が使われます。
(setq count 0) => 0 (defun count-syms (s) (setq count (1+ count))) => count-syms (mapatoms 'count-syms) => nil count => 1871
mapatoms
を用いた別の例は、section 説明文字列へのアクセスにある
documentation
を御覧ください。
symbol
が実際にはobarryに入っていなかった場合、unintern
は
なにもしません。obarrayがnil
の場合には現在のobarrayが使わ
れます。
symbolにシンボルの代わりに文字列が与えられた場合、これはシンボル
名であるとみなされます。そのうえでunintern
は、その名前を保持して
いるobarrayから(もしあれば)そのシンボルを消去します。そのようなシンボル
がないならば、unintern
はなにもしません。
unintern
はシンボルの消去を行なった場合にはt
を返します。
そうでなければnil
が返されます。
属性リスト(property list)(縮めてplist)はシンボルの属性リス ト・セルに格納された、要素を二つ単位でペアにしたリストのことです。 それぞれのペアは、属性の名前(通常はシンボル)と属性、いいかえれば値、を 結び付けます。属性リストは、シンボルに関する情報を記録しておくために広 く用いられ、たとえば変数としての説明やそのシンボルが定義されたファイル 名、さらにはひょっとすると言語解釈システムの中で(単語を表している)シン ボルの品詞を示すためにさえ利用されたりします。
文字列やバッファ内での文字の位置情報もまた属性リストをもつことが可能で す。See section テキスト属性。
属性リストにおける属性の名前と値は、どんなLispオブジェクトであっても構
わないのですが、名前はふつうシンボルです。それらは、eq
を使って比
較されます。以下に属性リストの例がありますが、これはコンパイラがロード
されたときにprogn
というシンボルにおいて見られるものです:
(lisp-indent-function 0 byte-compile byte-compile-progn)
ここでlisp-indent-function
とbyte-compile
が属性名であ
り、そのほかの要素はそれぞれに対応する値です。
連想リスト(see section 連想リスト)は属性リストととても似通っています。 連想リストとは対照的に、属性の名前は一意でなければならないため、属性リ スト内でのペアの順序は重要ではありません。
さまざまなLispの関数名や変数に情報を付加するためには、属性リストの方が
連想リストよりも優れています。もしも全ての連想情報が一つの連想リストに
記録されていた場合、関数や変数が操作されようとする度に、そのプログラム
はそのリスト全体を検索しなければなりません。対照的に、もしその情報がそ
の関数名や変数そのものの属性リストに記録されていれば、一回の検索は一つ
の属性リストの長さだけスキャンするだけですし、通常その長さは短いのです。
これが、変数に関する説明がvariable-documentation
という名前の属性
リストに記録されていることの理由です。同様に、バイトコンパイラは特殊
な取り扱いを必要とするような関数を記録するために属性リストを使います。
とはいうものの、連想リストにもそれなりの利点があります。アプリケーショ ンによっては、連想リストの先頭に連想情報を追加する方が、属性を更新する よりも速い場合があります。一つのシンボルに対する全ての属性は同一の属性 リストに格納されますから、一つの属性名に対して異なる用法がぶつかる可能 性があります(このため、おそらく一意であるような属性名、すなわち属性名に ライブラリの名前を含ませたようなものを選ぶのがよいでしょう)。連想リスト は、連想情報がリストの先頭にプッシュされ、後で捨てられるスタックのよう にして使われ得るものです。これは属性リストでは不可能です。
(setplist 'foo '(a 1 b (2 3) c nil)) => (a 1 b (2 3) c nil) (symbol-plist 'foo) => (a 1 b (2 3) c nil)
特殊なobarrayで、それが普通の用途に使われないような場合、その中に置かれ たシンボルに関しては、おかしな格好をした属性リスト・セルを用いることが 意味を持つ場合もあるかも知れません。 実際、省略形(abbrev)の機構ではそう しています(see section 省略形とその展開)。
nil
が返されます。したがって、nil
という値がある場合と属性が存在しな
い場合の区別はつきません。
propertyで与えられる名前は、存在している属性名とeq
を使っ
て比較されますから、どのようなオブジェクトでも合法的な属性になり得ます。
例としてput
を御覧ください。
put
関数は
valueを返します。
(put 'fly 'verb 'transitive) =>'transitive (put 'fly 'noun '(a buzzing little bug)) => (a buzzing little bug) (get 'fly 'verb) => transitive (symbol-plist 'fly) => (verb transitive noun (a buzzing little bug))
以下の二つの関数はシンボル以外の場所に格納された属性リストを扱うのに 便利です:
(plist-get '(foo 4) 'foo) => 4
(setq my-plist '(bar t foo 4)) => (bar t foo 4) (setq my-plist (plist-put my-plist 'foo 69)) => (bar t foo 69) (setq my-plist (plist-put my-plist 'quux '(a))) => (quux (a) bar t foo 5)
Go to the first, previous, next, last section, table of contents.