GNU Emacs Lispでシンボルがどのように生成されるかを理解するには、Lispがそれらをどのように読み取るかを知る必要があります。Lispは、同じコンテキストで同じ文字シーケンスを読み取るたびに、必ず同じシンボルを見つけられるようにしなければなりません。そうでなければ、完全な混乱を招くことになります。
Lispリーダーがソースコード内のシンボルを参照する名前に遭遇すると、obarrayと呼ばれるテーブルでその名前を検索し、プログラマが意図したシンボルを特定します。obarrayは、名前をインデックスとするシンボルの順序のないコンテナです。
Lispリーダーは「ショートハンド」も認識します。プログラマがこれらを定義していれば、ソースコード内にシンボル名が完全な形で記述されていなくても、リーダーはそのシンボルを特定できます。ショートハンドを参照してください。
目的の名前を持つシンボルが見つかった場合、リーダーはそのシンボルを使用します。obarrayにその名前のシンボルが含まれていない場合、リーダーは新しいシンボルを作成し、それをobarrayに追加します。特定の名前を持つシンボルを検索または追加することをインターニングと呼び、その結果得られたシンボルをインターニング済みシンボルと呼びます。
インターニングにより、各obarrayには特定の名前を持つシンボルがただ一つしか存在しなくなります。同様の名前を持つ他のシンボルが存在することはあっても、同じobarray内には存在しません。したがって、同じobarrayを用いて読み進める限り、読者は同じ名前に対して常に同じシンボルを得ることになります。
インターニングは通常、リーダー内で自動的に行われますが、他のプログラムがインターニングを行いたい場合もあります。例えば、M-xコマンドがミニバッファを用いてコマンド名を文字列として取得した後、その文字列をインターニングすることで、その名前を持つインターニング済みシンボルを取得します。別の例として、架空の電話帳プログラムであれば、obarrayに含まれていない場合でも、検索された各人物の名前をシンボルとしてインターニングし、最後に誰が検索したかといった情報をその新しいシンボルに紐付けることができます。
いかなる obarray にもすべてのシンボルが含まれているわけではなく、実際、いかなる obarray にも含まれないシンボルが存在します。これらは 未インターニング・シンボル と呼ばれます。未インターニング・シンボルは、他のシンボルと同様に4つのセルを持っていますが、これにアクセスする唯一の方法は、他のオブジェクト内や変数の値としてそれを見つけることです。未インターニング・シンボルは、Lispコードを生成する際に有用な場合があり、詳細は後述します。
Common Lispに関する注記: Common Lispとは異なり、Emacs Lispでは、同一の名前を複数の異なる「パッケージ」にインターニングして、同じ名前でパッケージが異なる複数のシンボルを作成することはできません。Emacs Lispでは、「ショートハンド」と呼ばれる別の名前空間システムが提供されています(ショートハンドを参照)。
この関数は、新しい obarray を作成して返します。オプションの size を使用して保持するシンボル数を指定できますが、obarray は必要に応じて自動的に拡張されるため、これが役立つことはほとんどありません。
この関数は、object が obarray であれば t を、そうでなければ nil を返します。
以下の関数の多くは、引数として名前、および場合によってはobarrayを取ります。名前が文字列でない場合、またはobarrayがobarrayオブジェクトでない場合は、wrong-type-argumentエラーが発生します。
この関数は、symbolの名前を表す文字列を返します。例えば:
(symbol-name 'foo)
⇒ "foo"
警告: その関数が返す文字列を絶対に変更しないでください。変更するとEmacsが正常に動作しなくなったり、最悪の場合はクラッシュしたりする恐れがあります。
アンインターンドシンボルを作成することは、Lispコードを生成する際に有用です。生成するコード内で変数として使用されるアンインターンドシンボルは、他のLispプログラムで使用されるいかなる変数とも衝突することがないためです。
この関数は、名前が name(文字列である必要があります)である、新たに割り当てられた未インターニングのシンボルを返します。その値と関数定義は
void であり、プロパティリストは nil です。以下の例では、sym の値は eq から foo ではありません。これは、名前が同じく ‘foo’ である別の未インターニングのシンボルであるためです。
(setq sym (make-symbol "foo"))
⇒ foo
(eq sym 'foo)
⇒ nil
この関数は make-symbol を用いたシンボルを返します。その名称は、prefix に gensym-counter
を付加し、そのカウンタをインクリメントすることで生成されるため、この関数を2回呼び出しても同一名称のシンボルが生成されることはありません。プレフィックスのデフォルト値は
"g" です。
生成されたコードの印刷表現(印刷表現と読み取り構文を参照)を誤ってインターニングした際に問題が発生するのを避けるため、make-symbol ではなく gensym
を使用することが推奨されます。
この関数は、名前が name であるインターニング済みシンボルを返します。obarray obarray にそのようなシンボルが存在しない場合、intern は新しいシンボルを作成して obarray に追加し、それを返します。obarray を省略した場合は、グローバル変数 obarray
の値が使用されます。
(setq sym (intern "foo"))
⇒ foo
(eq sym 'foo)
⇒ t
(setq sym1 (intern "foo" other-obarray))
⇒ foo
(eq sym1 'foo)
⇒ nil
Common Lispに関する注記: Common Lispでは、既存のシンボルをobarrayにinternできます。Emacs Lispでは、
internの引数はシンボルではなく文字列である必要があるため、この操作はできません。
この関数は、obarray の中で名前が name
であるシンボルを返します。obarray にその名前のシンボルが存在しない場合は、nil を返します。したがって、intern-soft
を使用して、指定した名前のシンボルが既にインターニングされているかどうかを判定できます。obarray
を省略した場合は、グローバル変数 obarray の値が使用されます。
引数 name はシンボルであってもよく、その場合、関数は name が指定された obarray にインターニングされていれば name を、そうでなければ nil を返します。
(intern-soft "frazzle") ; No such symbol exists. ⇒ nil (make-symbol "frazzle") ; Create an uninterned one. ⇒ frazzle
(intern-soft "frazzle") ; That one cannot be found.
⇒ nil
(setq sym (intern "frazzle")) ; Create an interned one.
⇒ frazzle
(intern-soft "frazzle") ; That one can be found!
⇒ frazzle
(eq sym 'frazzle) ; And it is the same one.
⇒ t
この変数は、intern および read
で使用する標準的な obarray です。
この関数は、obarray obarray 内の各シンボルに対して function を1回呼び出します。その後、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 を使用した別の例については、ドキュメント文字列へのアクセス の documentation を参照してください。
この関数は、obarray obarray から symbol を削除します。symbol が実際に
obarray に含まれていない場合、unintern は何もしません。obarray が nil である場合は、現在の obarray
が使用されます。
symbol にシンボルではなく文字列を指定すると、それはシンボル名を表します。すると unintern は、その名前を持つ obarray
内のシンボル(もしあれば)を削除します。そのようなシンボルが存在しない場合、unintern
は何もしません。
unintern がシンボルを削除した場合は、t
を返します。そうでない場合は、nil を返します。
この関数は、obarrayからすべての記号を削除します。