[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

2. Lispのデータ型

Lispオブジェクト(object)とは、 Lispプログラムが使用し操作するデータのことです。 (type)やデータ型(data type)とは、ここでは、 可能なオブジェクトの集合を意味します。

各オブジェクトは、少なくとも、1つの型に属します。 同じ型のオブジェクトは、構造に類似性があり、普通、同じ文脈で使われます。 型は互いに重複していてもよく、オブジェクトは複数の型に属することができます。 そのため、オブジェクトが特定の型に属するかどうかは判断できますが、 オブジェクトの型を『1つ』に限定することはできません。

Emacsには少数の基本オブジェクト型を組み込んであります。 これらの型は他のすべてのオブジェクト型を構成するもとであり、 基本型(primitive types)と呼びます。 各オブジェクトはたった1つの基本型に属します。 基本型には、 整数(integer)、浮動小数点数(float)、 コンス(cons)、シンボル(symbol)、 文字列(string)、ベクトル(vector)、subrバイトコード関数(byte-code function)、 ならびに、編集に関連するバッファ(buffer)などの 特別な型があります。 (see section 2.4 編集向けの型。)

各基本型には、その型に属するオブジェクトであるかどうかを検査する 対応するLisp関数があります。

Lispオブジェクトは型を自己記述(self-typing)するという点で、 Lispは他の多くの言語とは異なります。 つまり、オブジェクトの基本型は、オブジェクト自体に暗に含まれています。 たとえば、オブジェクトがベクトルであれば、それを数と扱うことはありません。 Lispには、ベクトルは数ではないとわかっているのです。

多くの言語では、プログラマは各変数のデータ型を宣言する必要があります。 型はコンパイラが知っているのであって、データの中には入っていません。 このような型宣言はEmacs Lispには存在しません。 Lisp変数はどんな型の値でも保持でき、 変数に入れた値と型を記録しています。

本章では、GNU Emacs Lispの各標準型の表示表現と入力構文を説明します。 これらの型の使用方法の詳細は、あとの章に譲ります。

2.1 表示表現と入力構文  How Lisp objects are represented as text.
2.2 コメント  Comments and their formatting conventions.
2.3 プログラミング向けの型  Types found in all Lisp systems.
2.4 編集向けの型  Types specific to Emacs.
2.5 型述語  Tests related to types.
2.6 同値述語  Tests of equality between any two objects.


2.1 表示表現と入力構文

オブジェクトの表示表現(printed representation)とは、 Lispプリンタ(関数prin1)がそのオブジェクトを出力表示するときの 書式です。 オブジェクトの入力構文(read syntax)とは、 Lispリーダ(関数read)がそのオブジェクトを入力として受理する書式です。 See section 18. Lispオブジェクトの読み取りと表示

ほとんどのオブジェクトには1つ以上の可能な入力構文があります。 ある種の型のオブジェクトには入力構文はありませんが、 そのような型のオブジェクトをLispプログラムに直接入力する意味がないからです。 このような場合を除くと、 オブジェクトの表示表現はそのオブジェクトの入力構文でもあります。

他の言語では、式はテキストであって、これ以外の形はありません。 Lispでは、式はとにかくLispオブジェクトであって、 オブジェクトの入力構文であるテキストは副次的なものです。 この違いを強調する必要はありませんが、 このことを心に留めておかないと混乱することがあります。

各型には表示表現があります。 入力構文のない型もあります。 たとえば、バッファ型には入力構文はありません。 このような型のオブジェクトはハッシュ記法(hash notation)で表示します。 つまり、文字列`#<'のあとに説明用の文字列 (典型的には型名にオブジェクトの名前を続けたもの)を続け、 対応する`>'で閉じます。 ハッシュ記法を読み取ることはできませんから、 Lispリーダが`#<'に出会うとエラーinvalid-read-syntaxを 通知します。

 
(current-buffer)
     => #<buffer objects.texi>

読者が対話的に式を評価するとき、 Lispインタープリタは、まず、 式のテキスト表現を読み取ってLispオブジェクトを生成し、 そのオブジェクトを評価します(see section 8. 評価)。 しかしながら、評価と読み取りは別々の動作です。 読み取りでは、読み取ったテキストが表すLispオブジェクトを返します。 このオブジェクトを、のちに評価する場合もありますが、 評価しない場合もあります。 オブジェクトを読み取る基本関数readについては、 See section 18.3 入力関数


2.2 コメント

コメント(comment)は、プログラム内に書かれたテキストであり、 プログラムを読む人間のためだけにあり、 プログラムの意味にはまったく影響しません。 Lispでは、文字列や文字定数の外にあるセミコロン(`;')で コメントを始めます。 コメントは行末までです。 Lispリーダは、コメントを破棄します。 コメントは、 Lispシステム内部でプログラムを表すLispオブジェクトの一部にはなりません。

`#@count'という書き方は、 後続のcount個の文字を飛び越します。 これは、プログラムで生成したバイナリデータを含むコメントに便利です。 Emacs Lispのバイトコンパイラは、出力ファイルにこのようなコメントを使います (see section 15. バイトコンパイル)。 しかしながら、ソースファイル向きではありません。

コメントの体裁に関する慣習については、See section A.4 コメントの書き方のヒント


2.3 プログラミング向けの型

Emacs Lispには、大きく2種類の型があります。 Lispのプログラミングに関わるものと、編集に関わるものです。 前者は、さまざまな形でLispの多くの実装に見られます。 後者は、Emacs Lispに固有です。

2.3.1 整数型  Numbers without fractional parts.
2.3.2 浮動小数点数  Numbers with fractional parts and with a large range.
2.3.3 文字型  The representation of letters, numbers and control characters.
2.3.4 シンボル型  A multi-use object that refers to a function, variable, or property list, and has a unique identity.
2.3.5 シーケンス型  Both lists and arrays are classified as sequences.
2.3.6 コンスセルとリスト型  Cons cells, and lists (which are made from cons cells).
2.3.7 配列型  Arrays include strings and vectors.
2.3.8 文字列型  An (efficient) array of characters.
2.3.9 ベクトル型  One-dimensional arrays.
2.3.10 文字テーブル型  One-dimensional sparse arrays indexed by characters.
2.3.11 ブールベクトル型  One-dimensional arrays of t or nil.
2.3.12 関数型  A piece of executable code you can call from elsewhere.
2.3.13 マクロ型  A method of expanding an expression into another expression, more fundamental but less pretty.
2.3.14 基本関数型  A function written in C, callable from Lisp.
2.3.15 バイトコード関数型  A function written in Lisp, then compiled.
2.3.16 自動ロード型  A type used for automatically loading seldom-used functions.


2.3.1 整数型

Emacs Lispにおける整数の値の範囲は、ほとんどの計算機では、 -134217728から134217727(28ビット長。つまり -2**27 から 2**27 - 1) です。 (計算機によっては、より広い範囲になる。) Emacs Lispの算術演算関数は、桁溢れ(オーバフロー)を 検査しないことを覚えておいてください。 したがって、ほとんどの計算機では、 (1+ 134217727)は-134217728となります。

整数の入力構文は、(10を基数とした)数字の並びであり、 先頭に符号があってもよく、また、最後にピリオドがあってもかまいません。 Lispインタープリタが生成する表示表現では、 先頭の`+'や最後の`.'はありません。

 
-1               ; 整数 -1
1                ; 整数 1
1.               ; これも整数 1
+1               ; これも整数 1
268435457        ; 28ビット長整数では、これも整数 1

より詳しくは、See section 3. 数


2.3.2 浮動小数点数

Emacsは浮動小数点数を扱えます (ただし、コンパイル時のオプションで使用不可にできる)。 浮動小数点数の範囲は、計算機に依存します。

浮動小数点数の表示表現には、 小数点(に続けて1桁以上の小数部分)または指数、 あるいは、その両方が必要です。 たとえば、`1500.0'、`15e2'、`15.0e2'、 `1.5e3'、`.15e4'は、同じ1500という値の 浮動小数点数を書く5つの方法です。 どれも、まったく等価です。

詳しくは、See section 3. 数


2.3.3 文字型

Emacs Lispにおける文字(character)は、 整数以外の何物でもありません。 いいかえれば、文字はその文字コードで表現されます。 たとえば、文字Aは整数 65と表現されます。

プログラムで個々の文字を独立に使うことはあまりありません。 文字を並べた文字列(strings)として扱うことが断然多いのです。 See section 2.3.8 文字列型

文字列内、バッファ内、ファイル内の文字は、 現時点では、0から524287までの範囲、19ビット長に制限されます。 しかし、この範囲の値すべてが正しい文字コードではありません。 0から127までのコードはASCIIコードです。 それ以外は、非ASCIIです(see section 32. 非ASCII文字)。 キーボード入力を表す文字は、コントロール、メタ、シフトなどの 修飾キーを符号化するために、範囲がより広くなります。

文字は、実際には整数ですから、文字の表示表現は10進数です。 また、文字の入力構文として10進数も可能ですが、 Lispプログラムでこのように文字を書くのは最悪です。 Emacs Lispに用意してある文字向けの特別な入力構文を つねに使うべきです。 これらの構文は疑問符で始まります。

英数字向けの普通の入力構文は、疑問符に続けて1つの英数字を書きます。 したがって、文字Aは`?A'、文字Bは`?B'、 文字aは`?a'と書きます。

たとえば、つぎのとおりです。

 
?Q => 81     ?q => 113

同じ入力構文を句読点文字にも使えますが、 `\'を追加して、Lispコードを編集するEmacsコマンドが混乱しないように することがよいでしょう。 たとえば、空白文字は`?\ 'と書きます。 文字`\'は、クォートするために2つめの`\'を使う必要があり `?\\'です。

コントロールg、バックスペース、タブ、改行、 垂直タブ、ページ送り、復帰、エスケープは、 それぞれ、`?\a'、`?\b'、`?\t'、`?\n'、`?\v'、 `?\f'、`?\r'、`?\e'と書きます。 つまり、つぎのとおりです。

 
?\a => 7                 ; C-g
?\b => 8                 ; バックスペース、 BSC-h
?\t => 9                 ; タブ、 TABC-i
?\n => 10                ; 改行、C-j
?\v => 11                ; 垂直タブ、C-k
?\f => 12                ; ページ送り文字、C-l
?\r => 13                ; 復帰、RET, C-m
?\e => 27                ; エスケープ文字、ESCC-[
?\\ => 92                ; バックスラッシュ文字、\

バックスラッシュで始まる系列は エスケープシーケンス(escape sequences)とも呼びます。 バックスラッシュが、エスケープ文字の役割を果たすからです。 この使い方は、文字ESCとは関係ありません。

コントロール文字は別の入力構文でも表現できます。 疑問符に続けてバックスラッシュ、カレット(`^')、そして、 対応するコントロールでない文字を大文字か小文字で書きます。 たとえば、`?\^I'も`?\^i'も、 値が9である文字C-iの正しい入力構文です。

カレットのかわりに、`C-'を使ってもかまいません。 ですから、`?\C-i'は、`?\^I'や`?\^i'と等価です。

 
?\^I => 9     ?\C-I => 9

文字列やバッファ内ではASCIIのコントロール文字だけが許されますが、 キーボード入力においては`C-'で任意の文字をコントロール文字にできます。 これらの非ASCIIコントロール文字の文字コードは、 対応する非コントロール文字の文字コードと 2**26 のビットを含みます。 普通の端末では、非ASCIIコントロール文字を生成する手立てはありませんが、 Xウィンドウシステムや他のウィンドウシステムでは、 簡単に生成できます。

歴史的な理由で、 EmacsはDEL文字を?に対応したコントロール文字として扱います。

 
?\^? => 127     ?\C-? => 127

その結果、今のところ、 Xウィンドウシステムのもとでは意味のある文字Control-?を `\C-'では表現できません。

ファイルや文字列に現れるコントロール文字を表現するには、 `^'構文を勧めます。 キーボード入力のコントロール文字には、`C-'構文が好ましいです。 どちらを使ってもプログラムの意味には影響しませんが、 それを読む人には理解の手助けになるかもしれません。

メタ文字(meta character)は、 META修飾キーを使って打った文字です。 そのような文字を表す整数は、(ほとんどの計算機では負の数になる) 2**27 のビットがセットされています。 上位のビットをメタや他の修飾子に用いることで、 基本となる文字コードの範囲をできるだけ大きくします。

文字列では、メタ文字を表すASCII文字には 2**7 のビットを付加します。 つまり、文字列に収められるメタ文字のコードは128から255の範囲であり、 任意のASCII文字のメタ変種を使えます。 (Emacs 18やそれ以前では、この方式を文字列の外にある文字にも使っていた。)

メタ文字の入力構文には`\M-'を使います。 たとえば、`?\M-A'はM-Aです。 `\M-'と一緒に8進文字コードも使えますし(下記参照)、 `\C-'や文字向けの他の構文も使えます。 したがって、M-Aは`?\M-A'と書いたり`?\M-\101'と書けます。 同様に、C-M-bは`?\M-\C-b'、 `?\C-\M-b'、`?\M-\002'と書けます。

図形文字の大文字小文字は、その文字コードで示されます。 たとえば、ASCIIでは`a'と`A'の文字を区別します。 しかし、ASCIIではコントロール文字の大文字小文字を表現できません。 Emacsでは、コントロール文字を打つときに使ったシフトキーを表すために 2**25 のビットを付加します。 このような区別はX端末や他の特別な端末を使っている場合に限り可能です。 普通の端末ではこのような区別を計算機に送れません。

Xウィンドウシステムでは、 文字に設定可能な修飾ビットが他に3つあります。 ハイパー(hyper)、スーパー(super)、アルト(alt)です。 これらの修飾ビットの構文は、 `\H-'、`\s-'、`\A-'です。 (これらのプレフィックスでは、大文字小文字を区別する。) したがって、`?\H-\M-\A-x'はAlt-Hyper-Meta-xを表します。 数値的には、 アルトは2**22、スーパーは2**23、ハイパーは2**24のビット値です。

文字向けのもっとも汎用の入力構文では、 文字コードを8進数や16進数で表現します。 8進数を使うには、順に、 疑問符、バックスラッシュ、(3桁までの)8進数字文字コードを書きます。 たとえば、`?\101'は文字Aを表し、 `?\001'は文字C-aを表し、?\002は文字C-bを表します。 この構文で任意のASCII文字を表現できますが、 ASCIIでの表現よりも8進数値で表現することが重要な場合に限るべきです。

 
?\012 => 10         ?\n => 10         ?\C-j => 10
?\101 => 65         ?A => 65

16進数を使うには、順に、疑問符、バックスラッシュ、 `x'、16進数字文字コードを書きます。 16進数の桁数はいくつでもよいので、任意の文字コードを表現できます。 したがって、`?\x41'は文字Aを表し、 `?\x1'は文字C-aを表し、 ?\x8e0は グレーブアクセント付きの文字`a'を表します。

特別なエスケープの意味を持たないどんな文字のまえにもバックスラッシュを 付けることができ、しかも、無害です。 したがって、`?\+'は`?+'に等価です。 ほとんどの文字のまえにバックスラッシュを付ける理由はありません。 しかしながら、Lispコードを編集するEmacsコマンドが混乱しないように、 `()\|;'`"#.,'のいずれかの文字のまえにはバックスラッシュを付けるべきです。 空白、タブ、改行、ページ送りのような白文字のまえにも バックスラッシュを付けるべきです。 しかしながら、タブなどの実際の白文字のかわりに、 `\t'などの読みやすいエスケープシーケンスを使ったほうが明確です。


2.3.4 シンボル型

GNU Emacs Lispにおけるシンボル(symbol)は、 名前を持ったオブジェクトです。 シンボル名は、シンボルの表示表現としての役割があります。 普通の使い方では、名前は一意です。 つまり、2つのシンボルが同じ名前を持つことはありません。

シンボルは、変数としての役割、関数名としての役割、 あるいは、属性リストを保持する役割を果たします。 また、他のすべてのLispオブジェクトと区別するためだけの役割を 果たすこともあり、データ構造の内部にそのようなシンボルが存在することを 正確に認識できます。 ある場面においては、普通、これらのうちの1つの使い方をします。 しかし、ある1つのシンボルに対してすべての使い方をしてもかまいません。

シンボル名には、どんな文字でも含められます。 ほとんどのシンボル名は、英文字、数字、`-+=*/'の句読点文字で書かれます。 そのような名前では、特別な書き方は必要ありません。 名前が数に見えなければ、名前を構成する文字はなんでもよいのです。 (名前が数に見えるときには、 名前の先頭に`\'を書いてシンボルであると強制する。) `_~!@$%^&:<>{}'の文字はあまり使われませんが、 これらにも特別な書き方は必要ありません。 これら以外の文字は、バックスラッシュでエスケープすれば、 シンボル名に含められます。 文字列におけるバックスラッシュの用法とは対照的に、 シンボル名におけるバックスラッシュは、直後の1文字をクォートするだけです。 たとえば、文字列では`\t'はタブ文字を表しますが、 シンボル名では英文字`t'をクォートするだけです。 名前にタブ文字を含むシンボルを書くには、 実際に(バックスラッシュの直後に)タブを使う必要があります。 しかし、そのようなことをするのは皆無でしょう。

Common Lispに関した注意: Common Lispでは、小文字を明示的にエスケープしない限り、 小文字をつねに大文字に『変換』する。 Emacs Lispでは、大文字と小文字を区別する。

シンボル名の例をいくつかあげましょう。 5番目の例の`+'は、数として読まれるのを防ぐために エスケープしてあることに注意してください。 6番目の例では、これは必要ありません。 なぜなら、名前の残りの部分が数としては不正だからです。

 
foo                 ; `foo'という名前のシンボル
FOO                 ; `FOO'という名前のシンボル、`foo'とは別
char-to-string      ; `char-to-string'という名前のシンボル
1+                  ; `1+'という名前のシンボル
                    ;   (整数の`+1'ではない)
\+1                 ; `+1'という名前のシンボル
                    ;   (読みにくい名前)
\(*\ 1\ 2\)         ; `(* 1 2)'という名前のシンボル(悪い名前)
+-*/_~!@$%^&=:<>{}  ; `+-*/_~!@$%^&=:<>{}'という名前のシンボル
                    ;   これらの文字をエスケープする必要はない


2.3.5 シーケンス型

シーケンス(sequence)とは、 要素の順序集合を表現するLispオブジェクトです。 Emacs Lispには2種類のシーケンス、つまり、リストと配列があります。 したがって、リスト型や配列型のオブジェクトは、 シーケンス型でもあると考えられます。

配列はさらに、文字列、ベクトル、文字テーブル、ブールベクトルに細分されます。 ベクトルは任意の型の要素を保持できますが、 文字列の要素は文字である必要があり、 ブールベクトルの要素はtnilのいずれかである必要があります。 バッファ内の文字のように、 文字列内の文字はテキスト属性を持てます(see section 31.19 テキスト属性)。 ベクトルとブールベクトル (5) では、それらの要素が文字であったとしても、 テキスト属性を扱えません。 文字テーブルは、ベクトルに似ていますが、正しい文字コードで添字付けします。

リスト、文字列、および、その他の配列型は別のものですが、 それらには重要な類似性があります。 たとえば、それらすべてに長さlがあり、 それらのすべての要素は0からl-1で添字付けできます。 シーケンス関数と呼ばれるいくつかの関数は、 任意のシーケンス型を扱います。 たとえば、シーケンスから指定した添字の要素を取り出すには、 関数eltを使います。 See section 6. シーケンス、配列、ベクトル

一般には、同一のシーケンスを二度読み取ることは不可能です。 というのは、読むたびにつねに新たにシーケンスを作成するからです。 シーケンスの入力構文を二度読むと、 同じ内容の2つのシーケンスを得ることになります。 1つ例外があります。 空リスト()は、つねに同じオブジェクトnilを表します。


2.3.6 コンスセルとリスト型

コンスセル(cons cell)とは、 CARスロットおよびCDRスロットと呼ばれる 2つのポインタから成るオブジェクトです。 各スロットは、任意のLispオブジェクトを指すことができます。 また、現在CARスロットが指しているオブジェクトがなんであれ、 『コンスセルのCARは』といったいい方をします。 CDRについても同様です。

リスト(list)はコンスセルが連なったものであり、 各コンスセルのCDRスロットは、 後続のコンスセルを指すか空リストを指します。 リストに作用する関数については、See section 5. リスト。 ほとんどのコンスセルは、リストの一部分として使われるので、 リスト構造(list structure)という用語は、 コンスセルから成る任意の構造のことを意味します。

CARやCDRという名称は、Lispの歴史に由来します。 最初のLispはIBM 704で動作していました。 この計算機では、ワードを2つの部分、『番地』(address)部分、 『減数』(decrement)部分と呼ばれるものに分けていました。 CARはレジスタの番地部分の内容(Contents of Address Register)を 取り出す命令であり、 CDRはレジスタの減数部分の内容(Contents of Decrement Register)を 取り出す命令でした。 一方、『コンスセル』という名称は、 これらを作成する関数consからきています。 この関数名は、その目的、セルを作る(construction of cells)からきています。

コンスセルはLispの核心なので、 『コンスセルではないオブジェクト』に対する名称もあります。 これらのオブジェクトをアトム(atoms)と呼びます。

リストの入力構文と表示表現は同一です。 開き括弧で始まり、任意個の要素、閉じ括弧で終えます。

読み取り時には、括弧の内側の各オブジェクトが、 リストの各要素になります。 つまり、これらの要素からなるコンスセルを作ります。 コンスセルのCARスロットで要素を指します。 同じコンスセルのCDRスロットで、 リスト上のつぎの要素を保持している、 リストのつぎのコンスセルを指します。 最後のコンスセルのCDRスロットはnilを指します。

リストは、コンスセルを1対の箱で表して図示できます。 (Lispリーダがこのような図表示を読むことはない。 人間や計算機が理解できるテキスト表記と違い、 箱を用いた図表示は人間だけが理解できる。) つぎの図は、3つの要素から成るリスト(rose violet buttercup)を表します。

 
    --- ---      --- ---      --- ---
   |   |   |--> |   |   |--> |   |   |--> nil
    --- ---      --- ---      --- ---
     |            |            |
     |            |            |
      --> rose     --> violet   --> buttercup

この図で、各箱は、任意のLispオブジェクトを指すことができるスロットを表します。 箱の対でコンスセルを表します。 各矢印は、アトムや他のコンスセルであるLispオブジェクトを指すポインタです。

この例では、最初のコンスセルのCARを表す最初の箱は、 rose(シンボル)を指しています。 あるいは、rose(シンボル)を『含んでいる』ともいいます。 最初のコンスセルのCDRを表す2番目の箱は、 つぎの1対の箱、2番目のコンスセルを指しています。 2番目のコンスセルのCARはvioletであり、 このコンスセルのCDRは3番目のコンスセルです。 3番目の(最後の)コンスセルのCDRは、nilです。

同じリスト(rose violet buttercup)を 別の方法で図表示するとつぎのようになります。

 
 ---------------       ----------------       -------------------
| car   | cdr   |     | car    | cdr   |     | car       | cdr   |
| rose  |   o-------->| violet |   o-------->| buttercup |  nil  |
|       |       |     |        |       |     |           |       |
 ---------------       ----------------       -------------------

内部に要素を持たないリストは、空リスト(empty list)です。 これはシンボルnilと同一です。 いいかえれば、nilはシンボルでもありリストでもあります。

Lispの構文で書き表したリストの例を示します。

 
(A 2 "A")            ; 3要素のリスト
()                   ; 要素を持たないリスト(空リスト)
nil                  ; 要素を持たないリスト(空リスト)
("A ()")             ; 文字列"A ()"だけの1要素のリスト
(A ())               ; Aと空リストから成る2要素のリスト
(A nil)              ; 上と同じ
((A B C))            ; 1要素のリスト
                     ;   (その要素は3要素のリスト)

リスト(A ())や、これと同じ(A nil)を 箱と矢印で書くとつぎのようになります。

 
    --- ---      --- ---
   |   |   |--> |   |   |--> nil
    --- ---      --- ---
     |            |
     |            |
      --> A        --> nil

2.3.6.1 ドット対記法  An alternative syntax for lists.
2.3.6.2 連想リスト型  A specially constructed list.


2.3.6.1 ドット対記法

ドット対記法(dotted pair notation)とは、 CARとCDRを明示したコンスセルを表すもう1つの構文です。 この構文では、(a . b)で、 CARがオブジェクトaであり CDRがオブジェクトbであるコンスセルを表します。 したがって、ドット対記法は、リストの構文よりさらに汎用性があります。 ドット対記法では、リスト`(1 2 3)'は、 `(1 . (2 . (3 . nil)))'と書けます。 nilで終るリストならば、どちらの記法でも書き表せますが、 リスト記法のほうがわかりやすくて便利です。 リストを表示するときには、コンスセルのCDRがリスト以外の場合に限って ドット対記法を使います。

ドット対記法を箱で表現してみます。 つぎの例は(rose . violet)を表したものです。

 
    --- ---
   |   |   |--> violet
    --- ---
     |
     |
      --> rose

最後のCDRがnil以外であるようなコンスセルの連鎖を表現するために、 リスト記法にドット対記法を組み合わせることもできます。 リストの最後の要素のあとにドットを書き、 続けて、最後のコンスセルのCDRを書きます。 たとえば、(rose violet . buttercup)は、 (rose . (violet . buttercup))に等価です。 このオブジェクトはつぎのようになります。

 
    --- ---      --- ---
   |   |   |--> |   |   |--> buttercup
    --- ---      --- ---
     |            |
     |            |
      --> rose     --> violet

(rose . violet . buttercup)という構文は不正です。 これが意味することはなにもありません。 たとえあったとしても、CDRをviolet用にすでに使っているコンスセルの CDRにbuttercupを置けということになります。

リスト(rose violet)は、(rose . (violet))に等価であり、 つぎのように図示できます。

 
    --- ---      --- ---
   |   |   |--> |   |   |--> nil
    --- ---      --- ---
     |            |
     |            |
      --> rose     --> violet

同様に、3要素のリスト(rose violet buttercup)は、 (rose . (violet . (buttercup)))に等価です。 つぎのように図示できます。

 
    --- ---      --- ---      --- ---
   |   |   |--> |   |   |--> |   |   |--> nil
    --- ---      --- ---      --- ---
     |            |            |
     |            |            |
      --> rose     --> violet   --> buttercup


2.3.6.2 連想リスト型

連想リスト(association list)、すなわち、alistは、 各要素がコンスセルであるように特別に構成したリストのことです。 各要素では、CARをキー(key)と考え、 CDRを連想値(associated value)と考えます。 (場合によっては、連想値を、CDRのCARに保持することもある。) 連想リストはスタックとして使われることがままあります。 というのは、リストの先頭に対応関係を追加/削除するのが簡単だからです。

たとえば、

 
(setq alist-of-colors
      '((rose . red) (lily . white)  (buttercup . yellow)))

は、変数alist-of-colorsに、3要素の連想リストを設定します。 最初の要素では、roseがキーであり、redが値です。

連想リストとそれらを操作する関数について詳しい説明は、 See section 5.8 連想リスト


2.3.7 配列型

配列(array)は、任意のLispオブジェクトを指すための 任意個のスロットから成り、メモリの連続した場所に取ります。 配列のどの要素を参照しても、ほぼ同じ時間かかります。 一方、リストの要素を参照するときには、 リスト内の要素の位置に比例した時間が必要です。 (リストの末尾の要素を参照するには、 リストの先頭の要素を参照するより時間がかかる。)

Emacsには、4つの配列型、つまり、 文字列、ベクトル、ブールベクトル、文字テーブルがあります。

文字列は文字の配列であり、 ベクトルは任意のオブジェクトの配列です。 ブールベクトルは、tnilだけを保持できます。 これらの種類の配列は、最大の整数値までなら、任意の長さにできます。 文字テーブルは、正しい文字コードで添字付けする疎な配列であり、 任意のオブジェクトを保持できます。

配列の最初の要素は0で添字付けする、 2番目の要素は1で添字付けする、というようになります。 これをゼロ原点(zero-origin)の添字付けと呼びます。 たとえば、4つの要素からなる配列の添字は、0、1、2、そして、3です。 最大の添字は、配列の長さより1だけ小さくなります。 いったん配列を作成すると、その長さは固定されます。

Emacs Lispのすべての配列は1次元です。 (多くの他のプログラム言語では多次元配列を扱えるが、 それは本質的ではない。 配列の配列を作れば同じ効果を得られる。) 配列のそれぞれの型に応じて、専用の入力構文があります。 詳しくは、以下を参照してください。

配列型はシーケンス型に含まれ、 配列型は、文字型、ベクトル型、ブールベクトル型、文字テーブル型を含みます。


2.3.8 文字列型

文字列(string)とは文字の配列です。 テキストエディタということから予想されるように、 Emacsではさまざまな目的に文字列を使います。 たとえば、Lispシンボルの名前として、 ユーザーへのメッセージとして、 バッファから取り出したテキストを表現するためなどです。 Lispの文字列は定数です。 つまり、文字列を評価すると同じ文字列になります。

文字列を操作する関数については、See section 4. 文字列と文字

2.3.8.1 文字列の構文  
2.3.8.2 文字列内の非ASCII文字  
2.3.8.3 文字列内の非印字文字  
2.3.8.4 文字列内のテキスト属性  


2.3.8.1 文字列の構文

文字列の入力構文は、"like this"のように、 ダブルクォートで始めて、任意個の文字を書き、ダブルクォートで終えます。 文字列の中にダブルクォートを含めるには、 バックスラッシュを直前に置きます。 つまり、"\""は、ダブルクォート1個だけから成る文字列です。 同様に、バックスラッシュを含めるには、 "this \\ is a single embedded backslash"のように、 バックスラッシュを直前に置きます。

文字列の入力構文において、改行文字は特別ではありません。 ダブルクォートのあいだに改行を書けば、 改行は文字列の文字になります。 一方、エスケープした改行、つまり、`\'を直前に書くと、 文字列の一部にはなりません。 すなわち、Lispリーダは、文字列を読む際にエスケープした改行を無視します。 エスケープした空白`\ 'も、同様に無視します。

 
"It is useful to include newlines
in documentation strings,
but the newline is \
ignored if escaped."
     => "It is useful to include newlines 
in documentation strings, 
but the newline is ignored if escaped."


2.3.8.2 文字列内の非ASCII文字

非ASCIIである国際化文字を文字列に含めるには、 その文字をそのまま書きます。 Emacsの文字列(および、バッファ)では、 非ASCIIの表現方法が2つあります。 ユニバイトとマルチバイトです。 マルチバイトバッファやマルチバイト文字列、あるいは、 マルチバイトとして訪問しているファイルなどの マルチバイトのソースから文字列定数を読み取るときには、 文字をマルチバイト文字として読み取り、 マルチバイト文字列にします。 ユニバイトのソースから文字列定数を読み取るときには、 文字をユニバイト文字として読み取り、 文字列はユニバイトになります。

マルチバイトの非ASCII文字は、 必要な桁数の16進エスケープ`\xnnnnnnn'を用いて 書くこともできます。 (マルチバイトの非ASCII文字のコードは、256より大きい。) 16進数字として正しくない文字で16進エスケープを終端します。 16進数字の文字があとに続く場合には、`\ '(バックスラッシュと空白)と 書いて16進エスケープを終端します。 たとえば、`\x8e0\ 'は、グレーブアクセント付きの`a'を表します。 文字列定数内の`\ 'は、バックスラッシュ+改行と同じです。 文字列内の文字には含まれませんが、先行する16進エスケープを終えます。

マルチバイトの16進エスケープを使うと、 文字列はマルチバイトになります。 ユニバイトの非ASCIIを文字コードで表現することもできますが、 文字コードは128(8進0200)から255(8進0377)の範囲である必要があります。 こうすると、文字列はユニバイトになります。 2種類のテキストの表現方法について詳しくは、See section 32.1 テキスト表現


2.3.8.3 文字列内の非印字文字

文字定数と同じバックスラッシュのエスケープシーケンスを文字列定数でも 使えます(ただし、文字定数を開始する疑問符は書かない)。 たとえば、コンマと空白で区切った非印字文字のタブとC-aを 含む文字列を書くには、"\t, \C-a"のようにします。 文字の入力構文については、See section 2.3.3 文字型

しかしながら、バックスラッシュのエスケープシーケンスすべてが、 文字列において正しいとは限りません。 文字列に含めることが可能なコントロール文字は、 ASCIIコントロール文字に限ります。 文字列では、ASCIIコントロール文字の大文字小文字を区別しません。

正確にいえば、文字列はメタ文字を保持できません。 しかし、文字列をキー列として使う場合には、 文字列内のASCII文字のメタ変種を表現するための 特別な慣習があります。 文字列定数内でメタ文字を表すために`\M-'の構文を使うと、 文字列内のその文字に 2**7 のビットを設定します。 define-keylookup-keyに文字列を使うと、 このコードは、等価なメタ文字に変換されます。 See section 2.3.3 文字型

文字列では、ハイパー、スーパー、アルトの修飾子を保持できません。


2.3.8.4 文字列内のテキスト属性

文字列は、文字そのものに加えて、文字の属性も保持できます。 このため、特別なことをしなくても、 文字列とバッファのあいだでテキストをコピーするプログラムは、 テキスト属性をコピーできます。 テキスト属性の意味については、See section 31.19 テキスト属性。 テキスト属性付きの文字列には、特別な入力構文があります。

 
#("characters" property-data...)

ここで、property-dataは0個以上のつぎのような3つ組みです。

 
beg end plist

3つ組みの要素、begendは整数であり、 文字列内の添字の範囲を表します。 plistはその範囲の属性リストです。 たとえば、

 
#("foo bar" 0 3 (face bold) 3 4 nil 4 7 (face italic))

は、最初の3文字がface属性としてboldを持ち、 最後の3文字がface属性としてitalicを持つ、 `foo bar'という文字列を表します。 (4番目の文字にはテキスト属性はなく、その属性リストはnil。 デフォルトでは、範囲に含まれない文字には属性はないので、 属性リストがnilであるような範囲を言及する必要はない。)


2.3.9 ベクトル型

ベクトル(vector)は、任意の型の要素から成る1次元配列です。 ベクトルの任意の要素を参照しても、それに必要な時間は一定です。 (リストでは、ある要素を参照するために必要な時間は、 リストの先頭からの距離に比例する。)

ベクトルの表示表現は、開き角括弧、要素、閉じ角括弧です。 これは、入力構文でもあります。 数や文字列と同様に、ベクトルは評価時には定数です。

 
[1 "two" (three)]      ; 3要素のベクトル
     => [1 "two" (three)]

ベクトルに作用する関数については、See section 6.4 ベクトル


2.3.10 文字テーブル型

文字テーブル(char-table)は、 任意の型の要素から成る1次元配列であり、 文字コードで添字付けします。 文字テーブルには、文字コードに情報を与えるための多くの操作を簡単にする 付加的な機能があります。 たとえば、文字テーブルは、情報を継承するための親、 デフォルト値、特定目的向けの少数の追加スロットを持てます。 文字テーブルでは、文字集合全体に対して1つの値を指定することもできます。

文字テーブルの表示表現はベクトルに似ていますが、 先頭に`#^'が余分に付きます。

文字テーブルを操作する特別の関数については、See section 6.6 文字テーブル。 文字テーブルはつぎのように使います。


2.3.11 ブールベクトル型

ブールベクトル(bool-vector)は、 tnilだけの要素から成る1次元配列です。

ブールベクトルの表示表現は文字列に似ていますが、 `#&'と長さで始まります。 これに続く文字列定数が、ブールベクトルの実際の内容を ビットマップで表します。 つまり、文字列の『各文字』は8ビット長のデータであり、 ブールベクトルのつぎの8個の要素を表します (1はtを表し、0はnilを表す)。 文字の最下位ビットが、ブールベクトルの小さい添字に対応します。 長さが8の倍数でない場合には、 表示表現には余計な要素が含まれますが、余計な部分に意味はありません。

 
(make-bool-vector 3 t)
     => #&3"\007"
(make-bool-vector 3 nil)
     => #&3"\0"
;; 最初の3ビットだけを使っているので、以下はすべて同じ
(equal #&3"\377" #&3"\007")
     => t


2.3.12 関数型

他のプログラム言語の関数が実行可能であるように、 Lisp関数(Lisp function)は実行可能なコードです。 しかしながら、Lispにおいては、関数は基本Lispオブジェクトであり、 そのテキスト表現は副次的なものです。 これらのLispオブジェクトはラムダ式です。 つまり、先頭要素がシンボルlambdaであるリストです (see section 11.2 ラムダ式)。

ほとんどのプログラム言語では、名前のない関数を書くことは不可能です。 Lispでは、本質的には、関数に名前はありません。 ラムダ式のことを無名関数(anonymous function)とも呼びます (see section 11.7 無名関数)。 Lispにおける名前付き関数は、実際には、 関数セルに正しい関数を収めたシンボルです (see section 11.4 関数を定義する)。

多くの場合、LispプログラムのLisp式中に関数名を書くと関数が呼ばれます。 しかし、実行時に関数オブジェクトを構成したり取得して、 基本関数funcallapplyで、それを呼び出すことができます。 See section 11.5 関数呼び出し


2.3.13 マクロ型

Lispマクロ(Lisp macro)は、 Lisp言語を拡張するユーザー定義の構造です。 関数に似たオブジェクトで表現しますが、引数渡しの意味は異なります。 Lispマクロは、リストの最初の要素がシンボルmacroであり、 リストのCDRがlambdaシンボルを 含むLisp関数オブジェクトであるフォームです。

Lispマクロオブジェクトは、通常、組み込み関数defmacroで 定義しますが、 Emacsにとっては、macroで始まるリストはマクロです。 マクロの書き方の説明は、See section 12. マクロ

警告 Lispマクロとキーボードマクロ (see section 20.14 キーボードマクロ)は、まったく別のものです。 単に『マクロ』といった場合には、Lispマクロを意味するのであって、 キーボードマクロのことではありません。


2.3.14 基本関数型

基本関数型(primitive function)は、 Lispから呼び出し可能な関数ですが、C言語で書いてあります。 基本関数のことをsubrとか 組み込み関数(built-in functions)とも呼びます。 (『subr』は『subroutine』からきている。) ほとんどの基本関数は、呼び出すときにすべての引数を評価します。 引数すべてを評価しない基本関数をスペシャルフォーム(special form)と 呼びます(see section 8.2.7 スペシャルフォーム)。

関数を呼び出す側からすれば、関数が基本関数かどうかは関係ありません。 しかし、Lispで書いた関数で基本関数を再定義しようとすると、 問題があります。 というのは、基本関数はCのコードから直接呼ばれるからです。 再定義した関数をLispから呼び出す場合には新しい定義を使いますが、 Cのコードは組み込みの定義を使い続けるでしょう。 したがって、基本関数を再定義しないでください

関数(function)という用語で、 LispやCで書かれたEmacsのすべての関数を指します。 Lispで書いた関数に関しては、See section 2.3.12 関数型

基本関数には入力構文はなく、 サブルーティン名を含むハッシュ記法で表示します。

 
(symbol-function 'car)          ; シンボルの関数セルを参照する
     => #<subr car>
(subrp (symbol-function 'car))  ; 基本関数か?
     => t                       ; そのとおり


2.3.15 バイトコード関数型

バイトコンパイラは、バイトコード関数オブジェクト (byte-code function objects)を作り出します。 内部的には、バイトコード関数オブジェクトはベクトルによく似ています。 しかしながら、評価過程においては、関数呼び出しのように見えるときには、 このデータ型を特別に扱います。 バイトコンパイラについては、See section 15. バイトコンパイル

バイトコード関数オブジェクトの表示表現と入力構文は、 ベクトルに似ていますが、開き角括弧`['のまえに`#'が付きます。


2.3.16 自動ロード型

自動ロードオブジェクト(autoload object)は、 先頭要素がシンボルautoloadであるリストです。 実際の定義のかわりにシンボルの関数定義として使われ、 必要なときにロードすべき実際の定義を収めたLispコードファイルを示します。 自動ロードオブジェクトには、ファイル名に加えて、 実際の関数定義に関する他の情報も入っています。

ファイルをロードし終えると、 シンボルには、自動ロードオブジェクトではない新たな関数定義が入ります。 この新たな定義を始めからあったかのように呼び出します。 ユーザーの視点からは、ロードしたファイル内の関数定義を使って、 予想どおりに関数呼び出しが行われます。

自動ロードオブジェクトは、普通、関数autoloadで作ります。 この関数は、シンボルの関数セルにオブジェクトを格納します。 より詳しくは、See section 14.4 自動ロード


2.4 編集向けの型

前節の型は一般のプログラム向けに使うもので、 そのほとんどは、ほんどのLisp方言に共通しています。 Emacs Lispには、編集に関連した目的向けにいくつかのデータ型があります。

2.4.1 バッファ型  The basic object of editing.
2.4.2 マーカ型  A position in a buffer.
2.4.3 ウィンドウ型  Buffers are displayed in windows.
2.4.4 フレーム型  Windows subdivide frames.
2.4.5 ウィンドウ構成型  Recording the way a frame is subdivided.
2.4.6 フレーム構成型  Recording the status of all frames.
2.4.7 プロセス型  A process running on the underlying OS.
2.4.8 ストリーム型  Receive or send characters.
2.4.9 キーマップ型  What function a keystroke invokes.
2.4.10 オーバレイ型  How an overlay is represented.


2.4.1 バッファ型

バッファ(buffer)は、編集可能なテキストを保持するオブジェクトです (see section 26. バッファ)。 ほとんどのバッファは、ディスクファイル(see section 24. ファイル)の内容を保持して 編集できるようにしますが、他の目的に使われるものもあります。 ほとんどのバッファは、ユーザーが見るためのものであり、 ある期間、ウィンドウ(see section 27. ウィンドウ)に表示されます。 しかし、バッファがいずれかのウィンドウに必ずしも表示される必要はありません。

バッファの内容は文字列によく似ていますが、 Emacs Lispにおいては、バッファは文字列のようには使われず、 適用可能な操作も異なります。 たとえば、既存のバッファにテキストを効率よく挿入できますが、 文字列にテキストを『挿入』するには、 部分文字列を連結する必要があり、まったく新しい文字列オブジェクトになります。

各バッファには、ポイント(point)と呼ばれる特別な箇所があります (see section 29. バッファ内の位置)。 どんなときにも、1つのバッファがカレントバッファ(current buffer)です。 ほとんどの編集コマンドは、カレントバッファのポイント付近の内容に作用します。 多くのEmacsの標準関数は、カレントバッファ内にある文字を操作したり検査します。 本書には、これらの関数の説明にあてた章が1つあります(see section 31. テキスト)。

各バッファに関連付けられたデータ構造には、つぎのものがあります。

ローカルキーマップと変数リストには、 それぞれ、グローバルな束縛や値に優先するものが入っています。 これらは、プログラムを変更せずに、各バッファごとに、 プログラムのふるまいをカスタマイズするために使われます。

バッファは間接(indirect)でもよく、その場合、 別のバッファとテキストを共有しつつ異なった表示を行えます。 See section 26.11 間接バッファ

バッファには入力構文はありません。 バッファ名を含んだハッシュ記法で表示します。

 
(current-buffer)
     => #<buffer objects.texi>


2.4.2 マーカ型

マーカ(marker)は、特定のバッファ内の位置を表します。 したがって、マーカには2つの構成要素、つまり、 バッファを示すものと位置を示すものがあります。 バッファ内のテキストを変更すると、 マーカがバッファ内の同じ2つの文字のあいだをつねに指すことを保証するように、 位置の値を更新します。

マーカには入力構文はありません。 バッファ内の文字位置とバッファ名を含んだハッシュ記法で表示します。

 
(point-marker)
     => #<marker at 10779 in objects.texi>

マーカの検査、作成、コピー、移動の方法については、See section 30. マーカ


2.4.3 ウィンドウ型

ウィンドウ(window)は、 Emacsがバッファを表示するために使用する端末画面の部分のことです。 各ウィンドウには、対応付けられたバッファが1つあり、 そのバッファの内容をウィンドウに表示しています。 一方、あるバッファが、1つのウィンドウや複数のウィンドウに表示されることもあり、 どのウィンドウにも表示されないこともあります。

同時に複数のウィンドウが存在できますが、 どんなときにも1つのウィンドウだけが選択されたウィンドウ (selected window)です。 これは、Emacsがコマンドを受け付け可能なときにカーソルを(通常)表示する ウィンドウです。 選択されたウィンドウは、通常、カレントバッファを表示しますが、 これは必須ではありません。

画面上のウィンドウはフレームにまとめられています。 各ウィンドウは、たった1つのフレームに属します。 See section 2.4.4 フレーム型

ウィンドウには入力構文はありません。 ウィンドウ番号と表示中のバッファ名を含んだハッシュ記法で表示します。 ウィンドウ番号は、ウィンドウを一意に識別するためにあります。 これは、ウィンドウが表示しているバッファは頻繁に変わるからです。

 
(selected-window)
     => #<window 1 on objects.texi>

ウィンドウを操作する関数の説明は、See section 27. ウィンドウ


2.4.4 フレーム型

フレーム(frame)は、画面上の矩形領域であって、 1つ以上のEmacsウィンドウを含みます。 フレームには最初は1つのウィンドウ (とミニバッファウィンドウ)が含まれますが、 これを左右や上下に小さなウィンドウに分割できます。

フレームには入力構文はありません。 フレームのタイトルとメモリ内のアドレス (フレームを一意に識別するのに有用)を含んだハッシュ記法で表示します。

 
(selected-frame)
     => #<frame emacs@psilocin.gnu.org 0xdac80>

フレームを操作する関数の説明は、See section 28. フレーム


2.4.5 ウィンドウ構成型

ウィンドウ構成(window configuration)は、 フレーム内のウィンドウの位置/サイズ/内容に関する情報を記録し、 同じ配置のウィンドウをあとで再度作成できるようにします。

ウィンドウ構成には入力構文はありません。 表示表現は、`#<window-configuration>'のようになります。 ウィンドウ構成に関連した関数の説明は、See section 27.16 ウィンドウ構成


2.4.6 フレーム構成型

フレーム構成(frame configuration)は、 すべてのフレームのウィンドウの位置/サイズ/内容に関する情報の記録です。 これは、実際には、リストのCARがframe-configurationであり、 リストのCDRが連想リストであるリストです。 連想リストの各要素で、そのCARに現れるフレーム1個を記述します。

フレーム構成に関連した関数の説明は、See section 28.12 フレーム構成


2.4.7 プロセス型

単語プロセス(process)は、通常、実行中のプログラムを意味します。 Emacs自身、この種のプロセスとして実行されています。 しかし、Emacs Lispでは、プロセスとは、 Emacsプロセスが作成したサブプロセスを表すLispオブジェクトのことです。 Emacsのサブプロセスで実行される、シェル、GDB、ftp、コンパイラなどの プログラムは、Emacsの能力を拡張します。

Emacsサブプロセスは、Emacsからテキスト入力を受け取り、 さらに処理できるようにEmacsにテキスト出力を返します。 Emacsはサブプロセスにシグナルを送ることもできます。

プロセスオブジェクトに入力構文はありません。 プロセス名を含んだハッシュ記法で表示します。

 
(process-list)
     => (#<process shell>)

プロセスを作成したり削除したり、プロセスに関する情報を返したり、 プロセスへ入力やシグナルを送ったり、プロセスから出力を受け取る 関数に関する情報は、See section 36. プロセス


2.4.8 ストリーム型

ストリーム(stream)は、文字を出し入れする対象、 つまり、入力用に文字を供給したり、出力として文字を受け取ったりといった ことに使えるオブジェクトです。 多くの異なる型をこのように使えます。 マーカ、バッファ、文字列、関数です。 ほとんどの場合、入力ストリーム(文字の供給源)は、 キーボード、バッファ、ファイルから文字を取得します。 出力ストリーム(文字の消費先)は、`*Help*'バッファなどのバッファや エコー領域に文字を送ります。

オブジェクトnilは、他の意味に加えて、 ストリームとしても使えます。 変数standard-inputstandard-outputの値になります。 また、オブジェクトtも、 ミニバッファ(see section 19. ミニバッファ)を使う入力ストリームや エコー領域への出力(see section 38.3 エコー領域)を意味します。

ストリームには表示形式も入力構文もなく、その基本型で表示します。

構文解析関数や表示関数を含むストリームに関連した関数の説明は、 See section 18. Lispオブジェクトの読み取りと表示


2.4.9 キーマップ型

キーマップ(keymap)は、ユーザーが打ったキーをコマンドに対応付けます。 この対応付けは、ユーザーのコマンド入力をどのように実行するかを制御します。 キーマップは、実際には、リストであり、 そのCARはシンボルkeymapです。

キーマップの作成、プレフィックスキーの扱い方、 グローバルやローカルなキーマップ、キーバインディングの変更に関する情報は、 See section 21. キーマップ


2.4.10 オーバレイ型

オーバレイ(overlay)は、バッファのある部分に作用する属性を指定します。 各オーバレイは、バッファの指定した範囲に作用し、 属性リスト(属性名と値の要素を交互に繰り返すリスト)を含んでいます。 オーバレイ属性は、 バッファの一部を一時的に異なった方式で表示するために使われます。 オーバレイ属性に入力構文はなく、 バッファ名と位置範囲を含んだハッシュ記法で表示します。

オーバレイの作成と使用法については、See section 38.8 オーバレイ


2.5 型述語

Emacs Lispインタープリタ自身は、関数を呼び出すときに渡す実引数の 型検査を行いません。 そうできないのは、他のプログラム言語が行うようには、 Lispの関数の引数にはデータ型の宣言がないからです。 したがって、各実引数がその関数で扱える型に属するかどうかを検査するのは、 各関数の責任です。

すべての組み込み関数は、必要なときには実引数の型検査を行い、 引数が誤った型であれば、エラーwrong-type-argumentを通知します。 たとえば、+に扱えない引数を渡すと、つぎのようになります。

 
(+ 2 'a)
     error--> Wrong type argument: number-or-marker-p, a

読者のプログラムで、異なる型を異なるように扱いたい場合には、 明示的に型検査を行う必要があります。 オブジェクトの型を検査するもっとも一般的な方法は、 型述語(type predicate)関数を呼び出すことです。 Emacsには、各型ごとに型述語があり、 型を組み合わせたものに対する述語もあります。

型述語関数は1つの引数を取ります。 引数が適切な型に属していればtを返し、 さもなければnilを返します。 述語関数に関するLisp一般の慣習に従って、 ほとんどの型述語の名前は`p'で終ります。

以下は、リストの検査に述語listpを使い、 シンボルの検査に述語symbolpを使う例です。

 
(defun add-on (x)
  (cond ((symbolp x)
         ;; Xがシンボルならば、それをLISTに加える
         (setq list (cons x list)))
        ((listp x)
         ;; Xがリストならば、その要素をLISTに追加する
         (setq list (append x list)))
        (t
         ;; シンボルとリストだけを扱う
         (error "Invalid argument %s in add-on" x))))

定義済みの型述語を、アルファベット順に、参照先を併記してあげておきます。

atom
see section atom

arrayp
see section arrayp

bool-vector-p
see section bool-vector-p

bufferp
see section bufferp

byte-code-function-p
see section byte-code-function-p

case-table-p
see section case-table-p

char-or-string-p
see section char-or-string-p

char-table-p
see section char-table-p

commandp
see section commandp

consp
see section consp

display-table-p
see section display-table-p

floatp
see section floatp

frame-configuration-p
see section frame-configuration-p

frame-live-p
see section frame-live-p

framep
see section framep

functionp
see section functionp

integer-or-marker-p
see section integer-or-marker-p

integerp
see section integerp

keymapp
see section keymapp

listp
see section listp

markerp
see section markerp

wholenump
see section wholenump

nlistp
see section nlistp

numberp
see section numberp

number-or-marker-p
see section number-or-marker-p

overlayp
see section overlayp

processp
see section processp

sequencep
see section sequencep

stringp
see section stringp

subrp
see section subrp

symbolp
see section symbolp

syntax-table-p
see section syntax-table-p

user-variable-p
see section user-variable-p

vectorp
see section vectorp

window-configuration-p
see section window-configuration-p

window-live-p
see section window-live-p

windowp
see section windowp

オブジェクトの型を調べるもっとも一般的な方法は、 関数type-ofを呼び出すことです。 各オブジェクトはたった1つの基本型に属することを思い出してください。 type-ofはどの1つかを教えてくれます(see section 2. Lispのデータ型)。 しかし、type-ofは、基本型以外についてはなにも知りません。 多くの場合、type-ofより型述語を使うほうが便利でしょう。

Function: type-of object
この関数は、objectの基本型を示すシンボルを返す。 その値は、 symbolintegerfloatstringconsvectorchar-tablebool-vectorsubrcompiled-functionmarkeroverlaywindowbufferframeprocesswindow-configurationの シンボルのうちの1つ。

 
(type-of 1)
     => integer
(type-of 'nil)
     => symbol
(type-of '())    ; ()nil
     => symbol
(type-of '(x))
     => cons


2.6 同値述語

2つのオブジェクトの同値関係を調べる2つの関数を説明します。 文字列などの特定のオブジェクトが同値であるかを調べる関数群もあります。 これらの述語については、データ型を述べている適切な章を参照してください。

Function: eq object1 object2
この関数は、object1object2が 同一オブジェクトであればtを返し、さもなければnilを返す。 『同一オブジェクト』とは、 一方を変更すると、他方にも同じ変更が反映されることを意味する。

eqは、object1object2が同じ値の整数であると tを返す。 また、シンボル名は、普通、一意であるので、 引数が同じ名前のシンボルであれば、それらはeqである。 (リスト、ベクトル、文字列などの)それ以外の型の場合、 2つの引数が同じ内容や要素であっても、 互いにeqであるとは限らない。 それらが同一オブジェクトである場合に限りeqである。

 
(eq 'foo 'foo)
     => t

(eq 456 456)
     => t

(eq "asdf" "asdf")
     => nil

(eq '(1 (2 (3))) '(1 (2 (3))))
     => nil

(setq foo '(1 (2 (3))))
     => (1 (2 (3)))
(eq foo foo)
     => t
(eq foo '(1 (2 (3))))
     => nil

(eq [(1 2) 3] [(1 2) 3])
     => nil

(eq (point-marker) (point-marker))
     => nil

関数make-symbolは、インターンしたシンボルを返す。 このシンボルは、Lisp式に書いた同じ名前のシンボルと区別される。 名前が同じでも区別されるシンボルはeqではない。 see section 7.3 シンボルの作成とインターン

 
(eq (make-symbol "foo") 'foo)
     => nil

Function: equal object1 object2
この関数は、 object1object2が等しい要素を持てばtを返し、 さもなければnilを返す。 eqは引数が同一オブジェクトかどうかを調べるが、 equalは、同一ではない引数の内部を調べ、 それらの要素が同じかどうかを調べる。 したがって、2つのオブジェクトがeqならば、 それらはequalであるが、その逆はつねに真とは限らない。

 
(equal 'foo 'foo)
     => t

(equal 456 456)
     => t

(equal "asdf" "asdf")
     => t
(eq "asdf" "asdf")
     => nil

(equal '(1 (2 (3))) '(1 (2 (3))))
     => t
(eq '(1 (2 (3))) '(1 (2 (3))))
     => nil

(equal [(1 2) 3] [(1 2) 3])
     => t
(eq [(1 2) 3] [(1 2) 3])
     => nil

(equal (point-marker) (point-marker))
     => t

(eq (point-marker) (point-marker))
     => nil

文字列の比較では大文字小文字を区別するが、テキスト属性は考慮しない。 つまり、文字列内の文字だけを比較する。 文字列の内容がすべてASCIIでなければ、 ユニバイト文字列とマルチバイト文字列が等しいことはない (see section 32.1 テキスト表現)。

 
(equal "asdf" "ASDF")
     => nil

たとえ内容が同じであっても、 異なる2つのバッファがequalであることはない。

equalの検査は再帰で実装されているので、 リストに循環があると無限再帰を引き起こし(エラーになり)ます。


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Akihiro Sagawa on January, 21 2003 using texi2html