GNU Emacs Lisp Reference Manual

For Emacs Version 27.1

by Bil Lewis, Dan LaLiberte, Richard Stallman,
the GNU Manual Group, et al.

This is the GNU Emacs Lisp Reference Manual corresponding to Emacs version 27.1.

Copyright © 1990–1996, 1998–2020 Free Software Foundation, Inc.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with the Invariant Sections being “GNU General Public License,” with the Front-Cover Texts being “A GNU Manual,” and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled “GNU Free Documentation License.”

(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and modify this GNU manual. Buying copies from the FSF supports it in developing GNU and promoting software freedom.”



Published by the Free Software Foundation
51 Franklin St, Fifth Floor
Boston, MA 02110-1301
USA
ISBN 1-882114-74-4



Cover art by Etienne Suvasa.


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

Emacs Lisp

This is the GNU Emacs Lisp Reference Manual corresponding to Emacs version 27.1.

Copyright © 1990–1996, 1998–2020 Free Software Foundation, Inc.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with the Invariant Sections being “GNU General Public License,” with the Front-Cover Texts being “A GNU Manual,” and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled “GNU Free Documentation License.”

(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and modify this GNU manual. Buying copies from the FSF supports it in developing GNU and promoting software freedom.”


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

1 イントロダクション

GNU Emacsテキストエディターのほとんどの部分は、Emacs Lispと呼ばれるプログラミング言語で記述されています。新しいコードをEmacs Lispで記述して、このエディターの拡張としてインストールできます。しかしEmacs Lispは、単なる拡張言語を越える言語であり、それ自体で完全なコンピュータープログラミング言語です。他のプログラミング言語で行なうすべてのことに、この言語を使用できます。

Emacs Lispはエディターの中で使用するようにデザインされているので、テキストのスキャンやパースのための特別な機能をもち、同様にファイル、バッファー、ディスプレー、サブプロセスを処理する機能をもちます。Emacs Lispは編集機能と密に統合されています。つまり編集コマンドはLispプログラムから簡単に呼び出せる関数で、カスタマイズのためのパラメーターは普通のLisp変数です。

このマニュアルはEmacs Lispの完全な記述を試みます。初心者のためのEmacs Lispのイントロダクションは、Free Software Foundationからも出版されている、Bob ChassellのAn Introduction to Emacs Lisp Programmingを参照してください。このマニュアルは、Emacsを使用した編集に熟知していることを前提としています。これの基本的な情報については、The GNU Emacs Manualを参照してください。

おおまかに言うと、前の方のチャプターでは多くのプログラミング言語の機能にたいして、Emacs Lispでの対応する機能を説明し、後の方のチャプターではEmacs Lispに特異な機能や、編集に特化した関連する機能を説明します。

これは Emacs 27.1に対応したGNU Emacs Lisp Reference Manualです。


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

1.1 注意事項

このマニュアルは幾多のドラフトを経てきました。ほとんど完璧ではありますが、不備がないとも言えません。(ほとんどの特定のモードのように)それらが副次的であるとか、まだ記述されていないという理由により、カバーされていないトピックもあります。わたしたちがそれらを完璧に扱うことはできないので、いくつかの部分は意図的に省略しました。

このマニュアルは、それがカバーしている事柄については完全に正しくあるべきあり、故に特定の説明テキスト、チャプターやセクションの順番にたいしての批判にオープンであるべきです。判りにくかったり、このマニュアルでカバーされていない何かを学ぶためにソースを見たり実地から学ぶ必要があるなら、このマニュアルはおそらく訂正されるべきなのかもしれません。どうかわたしたちにそれを教えてください。

このマニュアルを使用するときは、間違いを見つけたらすぐに訂正を送ってください。関数または関数グループの単純な現実例を考えたときは、ぜひそれを記述して送ってください。それが妥当ならコメントでノード名と関数名や変数名を参照してください。あなたが訂正を求めるエディションのバージョンも示してください。

M-x report-emacs-bugを使用して、コメントや訂正を送ってください。


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

1.2 Lispの歴史

Lisp(LISt Processing language: リスト処理言語)は、MIT(Massachusetts Institute of Technology: マサチューセッツ工科大学)で、AI(artificial intelligence: 人工知能)の研究のために、1950年代末に最初に開発されました。Lisp言語の強力なパワーは、編集コマンドの記述のような、他の目的にも適っています。

長年の間に何ダースものLisp実装が構築されてきて、それらのそれぞれに特異な点があります。これらの多くは、1960年代にMITのProject MACで記述された、Maclispに影響を受けています。最終的に、Maclisp後裔の実装者は共同して、Common Lispと呼ばれる標準のLispシステムを開発しました。その間にMITのGerry SussmanとGuy Steeleにより、簡潔ながらとても強力なLisp方言の、Schemeが開発されました。

GNU Emacs LispはMaclispから多く、Common Lispから少し影響を受けています。Common Lispを知っている場合、多くの類似点に気づくでしょう。しかしCommon Lispの多くの機能は、GNU Emacsが要求するメモリー量を削減するために、省略または単純化されています。ときには劇的に単純化されているために、Common Lispユーザーは混乱するかもしれません。わたしたちは時折GNU Emacs LispがCommon Lispと異なるか示すでしょう。Common Lispを知らない場合、それについて心配する必要はありません。このマニュアルは、それ自体で自己完結しています。

cl-libライブラリーを通じて、Common Lispをかなりエミュレートできます。Overview in Common Lisp Extensionsを参照してください。

Emacs LispはSchemeの影響は受けていません。しかしGNUプロジェクトにはGuileと呼ばれるScheme実装があります。拡張が必要な新しいGNUソフトウェアーでは、Guileを使用します。


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

1.3 表記について

このセクションでは、このマニュアルで使用する表記規約を説明します。あなたはこのセクションをスキップして、後から参照したいと思うかもしれません。


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

1.3.1 用語について

このマニュアルでは、“Lispリーダー”および“Lispプリンター”という用語で、Lispのテキスト表現を実際のLispオブジェクトに変換したり、その逆を行なうLispルーチンを参照します。詳細については、プリント表現と読み取り構文を参照してください。あなた、つまりこのマニュアルを読んでいる人のことはプログラマーと考えて“あなた”と呼びます。“ユーザー”とは、あなたの記述したものも含めて、Lispプログラムを使用する人を指します。

Lispコードの例は、(list 1 2 3)のようなフォーマットです。メタ構文変数(metasyntactic variables)を表す名前や、説明されている関数の引数名前は、first-numberのようにフォーマットされています。


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

1.3.2 nilt

Emacs Lispでは、シンボルnilには3つの異なる意味があります。1つ目は‘nil’という名前のシンボル、2つ目は論理値のfalse、3つ目は空リスト — つまり要素が0のリストです。変数として使用した場合、nilは常に値nilをもちます。

Lispリーダーに関する限り、‘()’と‘nil’は同一です。これらは同じオブジェクト、つまりシンボルnilを意味します。このシンボルを異なる方法で記述するのは、完全に人間の読み手を意図したものです。Lispリーダーが‘()’か‘nil’のどちらかを読み取った後は、プログラマーが実際にどちらの表現で記述したかを判断する方法はありません。

このマニュアルでは、空リストを意味することを強調したいときは()と記述し、論理値のfalseを意味することを強調したいときはnilと記述します。この慣習はLispプログラムで使用してもよいでしょう。

(cons 'foo ())                ; 空リストを強調
(setq foo-flag nil)           ; 論理値のfalseを強調

論理値が期待されているコンテキストでは、非niltrueと判断されます。しかし論理値のtrueを表す好ましい方法はtです。trueを表す値を選択する必要があり、他に選択の根拠がない場合はtを使用してください。シンボルtは、常に値tをもちます。

Emacs Lispでのniltは、常に自分自身を評価する特別なシンボルです。そのためプログラムでこれらを定数として使用する場合、クォートする必要はありません。これらの値の変更を試みると、結果はsetting-constantエラーとなります。変更不可な変数を参照してください。

Function: booleanp object

objectが2つの正規のブーリーン値(tnil)のいずれかなら、非nilをリターンする。


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

1.3.3 評価の表記

評価できるLisp式のことをフォーム(form)と呼びます。フォームの評価により、これは結果として常にLispオブジェクトを生成します。このマニュアルの例では、これを‘’で表します:

(car '(1 2))
     ⇒ 1

これは“(car '(1 2))を評価すると、1になる”と読むことができます。

フォームがマクロ呼び出しの場合、それは評価されるための新たなLispフォームに展開されます。展開された結果は‘’で表します。わたしたちは展開されたフォームの評価し結果を示すこともあれば、示さない場合もあります。

(third '(a b c))
     → (car (cdr (cdr '(a b c))))
     ⇒ c

1つのフォームを説明するために、同じ結果を生成する別のフォームを示すこともあります。完全に等価な2つのフォームは、‘’で表します。

(make-sparse-keymap) ≡ (list 'keymap)

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

1.3.4 プリントの表記

このマニュアルの例の多くは、それらが評価されるときにテキストをプリントします。(*scratch*バッファーのような)Lisp Interactionバッファーでコード例を実行する場合、プリントされるテキストはそのバッファーに挿入されます。(関数eval-regionでの評価のように)他の方法でコード例を実行する場合、プリントされるテキストはエコーエリアに表示されます。

このマニュアルの例はプリントされるテキストがどこに出力されるかに関わらず、それを‘-|’で表します。フォームを評価することにより戻される値は、‘’とともに後続の行で示します。

(progn (prin1 'foo) (princ "\n") (prin1 'bar))
     -| foo
     -| bar
     ⇒ bar

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

1.3.5 エラーメッセージ

エラーをシグナルする例もあります。これは通常、エコーエリアにエラーメッセージを表示します。エラーメッセージの行は‘error→’で始まります。‘error→’自体は、エコーエリアに表示されないことに注意してください。

(+ 23 'x)
error→ Wrong type argument: number-or-marker-p, x

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

1.3.6 バッファーテキストの表記

バッファー内容の変更を説明する例もあます。それらの例では、そのテキストのbefore(以前)とafter(以後)のバージョンを示します。それらの例では、バッファー内容の該当する部分を、ダッシュを用いた2行の破線(バッファー名を含む)で示します。さらに、‘’はポイントの位置を表します(もちろんポイントのシンボルはバッファーのテキストの一部ではなく、ポイントが現在配されている2つの文字のの位置を表す)。

---------- Buffer: foo ----------
This is the ∗contents of foo.
---------- Buffer: foo ----------

(insert "changed ")
     ⇒ nil
---------- Buffer: foo ----------
This is the changed ∗contents of foo.
---------- Buffer: foo ----------

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

1.3.7 説明のフォーマット

このマニュアルでは関数(function)、変数(variable)、コマンド(command)、ユーザーオプション(user option)、スペシャルフォーム(special form)を、統一されたフォーマットで記述します。記述の最初の行には、そのアイテムの名前と、もしあれば引数(argument)が続きます。 そのアイテムの属するカテゴリー(function、variableなど)は、行の先頭に表示します。 それ以降の行は説明行で、例を含む場合もあります。


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

1.3.7.1 関数の説明例

関数の記述では、関数の名前が最初に記述されます。同じ行に引数の名前のリストが続きます。引数の値を参照するために、引数の名前は記述の本文にも使用されます。

引数リストの中にキーワード&optionalがある場合、その後の引数が省略可能であることを示します(省略された引数のデフォルトはnil)。その関数を呼び出すときは、&optionalを記述しないでください。

キーワード&rest(これの後には1つの引数名を続けなければならない)は、その後に任意の引数を続けることができることを表します。&restの後に記述された引数名の値には、その関数に渡された残りのすべての引数がリストとしてセットされます。この関数を呼び出すときは、&restを記述しないでください。

以下はfooという架空の関数(function)の説明です:

Function: foo integer1 &optional integer2 &rest integers

関数foointeger2からinteger1を減じてから、その結果に残りすべての引数を加える。integer2が与えられなかった場合、デフォルトして数値19が使用される。

(foo 1 5 3 9)
     ⇒ 16
(foo 5)
     ⇒ 14

より一般的には、

(foo w x y…)
≡
(+ (- x w) y…)

慣例として引数の名前には、(たとえばintegerinteger1bufferのような)期待されるタイプ名が含まれます。(buffersのような)複数形のタイプは、しばしばその型のオブジェクトのリストを意味します。objectのような引き数名は、それが任意の型であることを表します(EmacsオブジェクトタイプのリストはLispのデータ型を参照)。他の名前をもつ引数(たとえばnew-file)はその関数に固有の引数で、関数がドキュメント文字列をもつ場合、引数のタイプはその中で説明されるべきです(ドキュメントを参照)。

&optional&restにより修飾される引数のより完全な説明は、ラムダ式を参照してください。

コマンド(command)、マクロ(macro)、スペシャルフォーム(special form)の説明も同じフォーマットですが、‘Function’が‘Command’、‘Macro’、‘Special Form’に置き換えられます。コマンドはとは単に、インタラクティブ(interactive: 対話的)に呼び出すことができる関数です。マクロは関数とは違う方法(引数は評価されない)で引数を処理しますが、同じ方法で記述します。

マクロとスペシャルフォームにたいする説明には、特定のオプション引数や繰り替えされる引数のために、より複雑な表記が使用されます。なぜなら引数リストが、より複雑な方法で別の引数に分離されるからです。‘[optional-arg]’はoptional-argがオプションであることを意味し、‘repeated-args’は0個以上の引数を表します。カッコ(parentheses)は、複数の引数をリスト構造の追加レベルにグループ化するのに使用されます。以下は例です:

Special Form: count-loop (var [from to [inc]]) body…

この架空のスペシャルフォームは、 bodyフォームを実行してから変数varをインクリメントするループを実装します。最初の繰り返しでは変数は値fromをもちます。以降の繰り返しでは、変数は1(incが与えられた場合はinc)増分されます。vartoに等しい場合、bodyを実行する前にループをexitします。以下は例です:

(count-loop (i 0 10)
  (prin1 i) (princ " ")
  (prin1 (aref vector i))
  (terpri))

fromtoが省略された場合、ループを実行する前にvarnilがバインドされ、繰り返しの先頭においてvarが非nilの場合は、ループをexitします。以下は例です:

(count-loop (done)
  (if (pending)
      (fixit)
    (setq done t)))

このスペシャルフォームでは、引数fromtoはオプションですが、両方を指定するか未指定にするかのいずれかでなければなりません。これらの引数が与えられた場合には、オプションでincも同様に指定することができます。これらの引数は、フォームのすべての残りの要素を含むbodyと区別するために、引数varとともにリストにグループ化されます。


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

1.3.7.2 変数の説明例

変数(variable)とは、オブジェクトにバインド(bind)される名前です(セット(set)とも言う)。変数がバインドされたオブジェクトのことを値(value)と呼びます。このような場合には、その変数が値をもつという言い方もします。ほとんどすべての変数はユーザーがセットすることができますが、特にユーザーが変更できる特定の変数も存在し、これらはユーザーオプション(user options)と呼ばれます。通常の変数およびユーザーオプションは、関数と同様のフォーマットを使用して説明されますが、それらには引数がありません。

以下は架空の変数electric-future-mapの説明です。

Variable: electric-future-map

この変数の値はElectric Command Futureモードで使用される完全なキーマップである。このマップ内の関数により、まだ実行を考えていないコマンドの編集が可能になる。

ユーザーオプションも同じフォーマットをもちますが、‘Variable’が‘User Option’に置き換えられます。


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

1.4 バージョンの情報

以下の機能は、使用しているEmacsに関する情報を提供します。

Command: emacs-version &optional here

この関数は実行しているEmacsのバージョンを説明する文字列をreturnすす。これはバグレポートにこの文字列を含めるときに有用である。

(emacs-version)
  ⇒ "GNU Emacs 26.1 (build 1, x86_64-unknown-linux-gnu,
             GTK+ Version 3.16) of 2017-06-01"

hereが非nilならテキストをバッファーのポイントの前に挿入して、nilをリターンする。この関数がインタラクティブに呼び出すと、同じ情報をエコーエリアに出力する。プレフィクス引数を与えると、hereが非nilになる。

Variable: emacs-build-time

この変数の値はEmacsがビルドされた日時を示す。値はcurrent-timeの形式(時刻を参照)、その情報が利用できなければnil

emacs-build-time
     ⇒ (20614 63694 515336 438000)
Variable: emacs-version

この変数の値は実行中のEmacsのバージョンであり、"26.1"のような文字列。"26.0.91"のように3つの数値コンポーネントをもつ値はリリース版ではなくテストバージョンであることを示す(Emacs 26.1より前では"25.1.1"のように文字列の最後に余分な整数コンポーネントが含まれていたが、これは現在はemacs-build-numberに格納される)。

Variable: emacs-major-version

Emacsのメジャーバージョン番号を示す整数。Emacs 23.1では値は23。

Variable: emacs-minor-version

Emacsのマイナーバージョン番号を示す整数。Emacs 23.1では値は1。

Variable: emacs-build-number

これは同一のディレクトリーにおいてEmacsが(クリーニングなしで)ビルドされるたびに増分される整数。これはEmacsの開発時だけに関係のある変数。

Variable: emacs-repository-version

Emacsがビルドされたリポジトリのリビジョン番号を与える文字列。Emacsがリビジョンコントロール外部でビルドされた場合の値はnil

Variable: emacs-repository-branch

Emacsがビルドされたリポジトリブランチを与える文字列。ほとんどの場合は"master"。Emacsがリビジョンコントロール外部でビルドされた場合の値はnil


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

1.5 謝辞

このマニュアルは当初、Robert Krawitz、Bil Lewis、Dan LaLiberte、Richard M. Stallman、Chris Welty、およびGNUマニュアルグループのボランティアにより、数年を費やして記述されました。Robert J. Chassellはこのマニュアルのレビューと編集をDefense Advanced Research Projects Agency、ARPA Order 6082のサポートのもとに手助けしてくれ、Computational Logic, IncのWarren A. Hunt, Jr.によりアレンジされました。それ以降も追加のセクションがMiles Bader、Lars Brinkhoff、Chong Yidong、Kenichi Handa、Lute Kamstra、Juri Linkov、Glenn Morris、Thien-Thi Nguyen、Dan Nicolaescu、Martin Rudalics、Kim F. Storm、Luc Teirlinck、Eli Zaretskii、およびその他の人たちにより記述されました。

Drew Adams、Juanma Barranquero、Karl Berry、Jim Blandy、Bard Bloom、Stephane Boucher、David Boyes、Alan Carroll、Richard Davis、Lawrence R. Dodd、Peter Doornbosch、David A. Duff、Chris Eich、Beverly Erlebacher、David Eckelkamp、Ralf Fassel、Eirik Fuller、Stephen Gildea、Bob Glickstein、Eric Hanchrow、Jesper Harder、George Hartzell、Nathan Hess、Masayuki Ida、Dan Jacobson、Jak Kirman、Bob Knighten、Frederick M. Korz、Joe Lammens、Glenn M. Lewis、K. Richard Magill、Brian Marick、Roland McGrath、Stefan Monnier、Skip Montanaro、John Gardiner Myers、Thomas A. Peterson、Francesco Potortì、Friedrich Pukelsheim、Arnold D. Robbins、Raul Rockwell、Jason Rumney、Per Starbäck、Shinichirou Sugou、Kimmo Suominen、Edward Tharp、Bill Trost、Rickard Westman、Jean White、Eduard Wiebe、Matthew Wilding、Carl Witty、Dale Worley、Rusty Wright、David D. Zuhnにより訂正が提供されました。

より完全な貢献者のリストは、Emacsソースリポジトリーの関連する変更ログエントリーを参照してください。


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

2 Lispのデータ型

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

すべてのオブジェクトは少なくとも1つの型に属します。同じ型のオブジェクトは同様な構造をもち、通常は同じコンテキストで使用されます。型を重複してもつことができ、オブジェクトは複数の型に属することができます。その結果として、あるオブジェクトが特定の型に属するかどうかを尋ねることはできますが、オブジェクトがその型だけに属するかどうかは決定できません。

Emacsにはいくつかの基本オブジェクト型が組み込まれています。これらの型は他のすべての型を構成するもとであり、プリミティブ型(primitive types: 基本型)と呼ばれます。すべてのオブジェクトはただ1つのプリミティブ型に属します。これらの型には整数(integer)浮動小数点数(float)コンス(cons)シンボル(symbol)文字列(string)ベクター(vector)ハッシュテーブル(hash-table)サブルーチン(subr)バイトコード関数(byte-code function)レコード(record)、およびbufferのような編集に関連した特別な型が含まれます(編集用の型を参照)。

プリミティブ型にはそれぞれ、オブジェクトがその型のメンバーかどうかのチェックを行なうために、それぞれ対応するLisp関数があります。

他の多くの言語とは異なり、Lispのオブジェクトは自己記述(self-typing)的です。オブジェクトのプリミティブ型は、オブジェクト自体に暗に含まれます。たとえばオブジェクトがベクターなら、それを数字として扱うことはできません。Lispはベクターが数字でないことを知っているのです。

多くの言語では、プログラマーは各変数にたいしてデータ型を宣言しなければならず、コンパイラーは型を知っていますが、データの中に型はありません。Emacs Lispには、このような型宣言はありません。Lisp変数は任意の型の値をもつことができ、変数に保存した値と型を記憶します(実際には特定の型の値だけをもつことができる少数のEmacs Lisp変数がある。値を制限された変数を参照されたい)。

このチャプターでは、GNU Emacs Lispの各標準型の意味、プリント表現(printed representation)、入力構文(read syntax)を説明します。これらのデータ型を使用する方法についての詳細は、以降のチャプターを参照してください。


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

2.1 プリント表現と読み取り構文

オブジェクトのプリント表現(printed representation)とは、オブジェクトにたいしてLispプリンター(関数prin1)が生成する出力のフォーマットです。すべてのデータ型は一意なプリント表現をもちます。オブジェクトの入力構文(read syntax)とは、オブジェクトにたいしてLispリーダー(関数read)が受け取る入力のフォーマットです。これは一意である必要はありません。多くの種類のオブジェクトが複数の構文をもちます。Lispオブジェクトの読み取りとプリントを参照してください。

ほとんどの場合、オブジェクトのプリント表現が、入力構文としても使用されます。しかしLispプログラム内の定数とすることに意味が無いいくつかの型には、入力構文がありません。これらのオブジェクトはハッシュ表記(hash notation)でプリントされ、‘#<’、説明的な文字列(典型的には型名にオブジェクトの名前を続けたもの)、‘>’で構成される文字列です。たとえば:

(current-buffer)
     ⇒ #<buffer objects-ja.texi>

ハッシュ表記は読み取ることができないので、Lispリーダーは‘#<’に遭遇すると常にエラーinvalid-read-syntaxをシグナルします。

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

インタラクティブに式を評価するとき、Lispインタープリターは最初にそれのテキスト表現を読み取り、Lispオブジェクトを生成してからそのオブジェクトを評価します(評価を参照)。しかし評価と読み取りは別の処理です。読み取りによりテキストにより表現されたLispオブジェクトを読み取り、Lispオブジェクトがリターンされます。後でオブジェクトは評価されるかもしれないし、評価されないかもしれません。オブジェクトを読み取るための基本的な関数readの説明は、入力関数を参照してください。


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

2.2 特別な読み取り構文

Emacs Lispでは特別なハッシュ表記を通じて多くの特別なオブジェクトと構文を表します。

#<…>

入力構文がないオブジェクトはこのように表される(プリント表現と読み取り構文を参照)。

##

名前が空文字列であるようなインターン済みシンボルのプリント表現(シンボル型を参照)。

#'

functionにたいするショートカット。無名関数を参照のこと。

#:

名前がfooであるようなインターンされていないシンボルのプリント表現は‘#:foo’ (シンボル型を参照)。

#N

循環構造のプリント時には構造が自身をループバックすることを表すためにこの構文が使用される。ここで‘N’リストの開始カウント。

(let ((a (list 1)))
  (setcdr a a))
=> (1 . #0)
#N=
#N#

#N=’はオブジェクト名、‘#N#’はそのオブジェクトを表すので、これらはコピーではなく同一オブジェクトになる(循環オブジェクトの読み取り構文を参照)。

#@N

次の‘N’文字をスキップする(コメントを参照)。

#xN

16進表現の‘N’ (‘#x2a’)。

#oN

8進表現の‘N’ (‘#o52’)。

#bN

2進表現の‘N’ (‘#b101010’)。

#(…)

文字列のテキストプロパティ(文字列内のテキストプロパティを参照)。

#^

文字テーブル(文字テーブル型を参照)。

#s(hash-table …)

ハッシュテーブル(ハッシュテーブル型を参照)。

?C

文字(基本的な文字構文を参照)。

#$

バイトコンパイル済みファイルのカレントファイル名(ドキュメント文字列とコンパイルを参照)。これはEmacs Lispソースファイルで使用するためのものではない。

#@N

次の‘N’文字をスキップする(コメントを参照)。バイトコンパイル済みファイル内で使用されるものであって、Emacs Lispソースファイル内で使用するためのものではない。


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

2.3 コメント

コメント(comment)はプログラム中に記述されたテキストであり、そのプログラムを読む人間ためだけに存在するものであって、プログラムの意味には何の影響ももちません。Lispではそれが文字列や文字定数にある場合をのぞき、エスケープされていないセミコロン(‘;’)でコメントが開始されます。行の終端までがコメントになります。Lispリーダーはコメントを破棄します。コメントはLispシステム内でプログラムを表すLispオブジェクトの一部にはなりません。

#@count’構成は、次のcount個の文字をスキップします。これはプログラムにより生成されたバイナリーデータを含むコメントにたいして有用です。Emacs Lispバイトコンパイラーは出力ファイルにこれを使用します(バイトコンパイルを参照)。しかしソースファイル用ではありません。

コメントのフォーマットにたいする慣例は、コメント記述のヒントを参照してください。


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

2.4 プログラミングの型

Emacs Lispには2種類の一般的な型があります。1つはLispプログラミングに関わるもので、もう1つは編集に関わるものです。前者はさまざまな形で多くのLisp実装に存在します。後者はEmacs Lispに固有です。


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

2.4.1 整数型

内部にはfixnumsと呼ばれる小さい整数、およびbignumsという大きい整数という2種類の整数が存在します。

fixnumの値の範囲はマシンに依存します、最小のレンジは-536,870,912から536,870,911(30ビットでは -2**29 から 2**29 - 1) しかし多くのマシンはより広い範囲を提供します。

bignumは任意の精度をもつことができます。fixnumのオーバーフローする処理では、かわりにbignumをリターンされます。

eql=ですべての数値、fixnumならeqで比較することができます。整数がfixnumかbignumをテストするにはmost-negative-fixnummost-positive-fixnumで比較するか、便利な述語fixnumpbignumpを任意のオブジェクトに使用できます。

整数にたいする入力構文は、(10を基数とする)数字のシーケンスで、オプションで先頭に符号、最後にピリオドがつきます。Lispインタープリターにより生成されるプリント表現には、先頭の ‘+’や最後の‘.’はありません。

-1               ; 整数の-1
1                ; 整数の1
1.               ; これも整数の1
+1               ; これも整数の1

詳細は数値を参照してください。


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

2.4.2 浮動小数点数型

浮動小数点数は、コンピューターにおける科学表記に相当するものです。浮動小数点数を10の指数をともなう有理数として考えることができます。正確な有効桁数と可能な指数はマシン固有です。Emacsは値の保存にCデータ型のdoubleを使用し、内部的には10の指数ではなく、2の指数として記録します。

浮動小数点数のプリント表現には、(後に最低1つの数字をともなう)小数点と、指数のどちらか一方、または両方が必要です。たとえば‘1500.0’、‘+15e2’、‘15.0e+2’、‘+1500000e-3’、‘.15e4’は、いずれも浮動小数点数の1500を記述し、これらはすべて等価です。

詳細は数値を参照してください。


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

2.4.3 文字型

Emacs Lispでの文字(character)は、整数以外の何者でもありません。言い換えると、文字は文字コードで表現されます。たとえば文字Aは、整数の65として表現されます。

プログラムで文字を個別に使用するのは稀であり、文字のシーケンスとして構成される文字列(strings)として扱われるのがより一般的です。文字列型を参照してください。

文字列やバッファーの中の文字は、現在のところ0から4194303の範囲 — つまり22ビットに制限されています(文字コードを参照)。0から127のコードはASCIIコードで、残りは非ASCIIです(ASCII文字を参照)。キーボード入力を表す文字はコントロール(Control)、メタ(Meta)、シフト(Shift)などの修飾キーをエンコードするために、より広い範囲をもちます。

文字から可読なテキスト記述を生成する、メッセージ用の特別な関数が存在します。ヘルプメッセージの文字記述を参照してください。


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

2.4.3.1 基本的な文字構文

文字は実際には整数なので、文字のプリント表現は10進数です。文字にたいする入力構文も利用可能ですが、Lispプログラムでこの方法により文字を記述するのは、明解なプログラミングではありません。文字にたいしては、Emacs Lispが提供する、特別な入力構文を常に使用するべきです。これらの構文フォーマットはクエスチョンマークで開始されます。

英数字にたいする通常の入力構文は、クエスチョンマークと、その後にその文字を記述します。したがって文字Aは‘?A’、文字Bは‘?B’、文字aは‘?a’となります。

たとえば:

?Q ⇒ 81     ?q ⇒ 113

区切り文字(punctuation characters)にも同じ構文を使用できますが、区切り文字がLispで特別な意味をもつ場合には‘\\’でクォートしなければなりません。たとえば‘?\\(’が開カッコを記述する方法であり、同様に文字が‘\’なら、‘?\\’のようにクォートするために2つ目の‘\’を使用しなければなりません。

Ctrl+g(control-g)、バックスペース(backspace)、タブ(tab)、改行(newline)、垂直タブ(vertical tab)、フォームフィード(formfeed)、スペース(space)、キャリッジリターン(return)、デリート(del)、エスケープ(escape)はそれぞれ‘?\a’、‘?\b’、‘?\t’、‘?\n’、‘?\v’、‘?\f’、‘?\s’、‘?\r’、‘?\d’、‘?\e’と表すことができます(後にダッシュのついた‘?\s’は違う意味をもつ — これは後続の文字にたいしてスーパーによる修飾を適用する)。したがって、

?\a ⇒ 7                 ; control-g、C-g
?\b ⇒ 8                 ; バックスペース、BSC-h
?\t ⇒ 9                 ; タブ、TABC-i
?\n ⇒ 10                ; 改行、C-j
?\v ⇒ 11                ; 垂直タブ、C-k
?\f ⇒ 12                ; フォームフィード文字、C-l
?\r ⇒ 13                ; キャリッジリターン、RETC-m
?\e ⇒ 27                ; エスケープ文字、ESCC-[
?\s ⇒ 32                ; スペース文字、SPC
?\\ ⇒ 92                ; バックスラッシュ文字、\
?\d ⇒ 127               ; デリート文字、DEL

バックスラッシュがエスケープ文字の役割を果たすので、これらのバックスラッシュで始まるシーケンスはエスケープシーケンス(escape sequences)とも呼ばれます。この用語法は文字ESCとは関係ありません。‘\s’は文字定数としての使用を意図しており、文字定数の内部では単にスペースを記述します。

エスケープという特別な意味を与えずに、任意の文字の前にバックスラッシュの使用することは許されていて害もありません。したがって‘?\+’は‘?+’と等価です。ほとんどの文字の前にバックスラッシュを追加することに理由はありません。しかし文字‘()[]\;"’の前にはバックスラッシュを追加しなければならず、Lispコードを編集するEmacsコマンドが混乱するのを避けるために‘|'`#.,’の前にもバックスラッシュを追加するべきです。コードを読む人の混乱を避けるために、前に言及したASCII文字と類似したUnicode文字の前にもバックスラッシュを追加する必要があります。これを奨励するために、‘’のような一般的には混乱を招くエスケープされていない文字をハイライトします。スペース、タブ、改行、フォームフィードのような空白文字の前にもバックスラッシュを追加できます。しかしタブやスペースspaceのような実際の空白文字のかわりに、‘\t’や‘\s’のような可読性のあるエスケープシーケンスを使用するほうが明解です(スペースを後にともなうバックスラッシュを記述する場合、後続のテキストと区別するために、文字定数の後に余分なスペースを記述すること)。


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

2.4.3.2 一般的なエスケープ構文

特に重要なコントロール文字にたいする特別なエスケープシーケンスに加えて、Emacsは非ASCIIテキスト文字の指定に使用できる、何種類かのエスケープ構文を提供します。

  1. もしあればUnicode名で文字を指定できる。?\N{NAME}NAMEという名前のUnicode文字を表す。したがって‘?\N{LATIN SMALL LETTER A WITH GRAVE}’はと等価でありUnicode文字のU+00E0を意味する。名前中のスペースを空白文字(改行)の非空のシーケンスにして複数行文字列の入力を簡略化できる。
  2. Unicode値で文字を指定できる。?\N{U+X}はUnicodeコードポイントX (16進数値)を表す。また?\uxxxx?\Uxxxxxxxxはそれぞれコードポイントxxxxxxxxxxxxを表すxは(1つの16進数字)。たとえば?\N{U+E0}?\u00e0?\U000000E0と‘?\N{LATIN SMALL LETTER A WITH GRAVE}’に等しい。Unicode標準は‘U+10ffff’以下のコードポイントだけを定義するので、これより大きいコードポイントではEmacsはエラーをシグナルする。
  3. 文字を16進の文字コードで指定できる。16進エスケープシーケンスはバックスラッシュ、‘x’、および16進の文字コードにより構成される。したがって‘?\x41’は文字A、‘?\x1’は文字C-a?\xe0は文字à (グレイブアクセントつきのa)になる。任意の16進数を使用できるので、この方法で任意の文字を表すことができる。
  4. 8進の文字コードにより文字を指定できる。8進エスケープシーケンスは3桁までの8進数字をともなうバックスラッシュにより形成される。したがって‘?\101’は文字A、‘?\001’は文字C-a?\002は文字C-bを表す。この方法で指定できるのは8進コード777までの文字のみ。

これらのエスケープシーケンスは文字列内でも使用されます。文字列内の非ASCII文字を参照してください。


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

2.4.3.3 コントロール文字構文

他の入力構文を使用してコントロール文字を表すことができます。これは後にバックスラッシュ、カレット、対応する非コントロール文字(大文字か小文字)をともなうクエスチョンマークから構成されます。たとえば‘?\^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-’を使用して表現することは今のところできません。さまざまなLispファイルがこの方法でDELを参照するので、これを変更するのは簡単ではないのです。

コントロール文字の表現はファイルや文字列内で見ることができますが、わたしたちは‘^’構文を推奨します。キーボード入力にたいするコントロール文字に好ましいのは、‘C-’構文です。どちらを使用するかはプログラムの意味に影響しませんが、プログラムを読む人の理解を助けるでしょう。


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

2.4.3.4 メタ文字構文

メタ文字(meta character)とは、META修飾キーとともにタイプされた文字です。そのような文字を表す整数には 2**27 のビットがセットされています。基本的な文字コードの広い範囲を利用可能にするために、メタやその他の修飾にたいしては上位ビットを使用します。

文字列では、メタ文字を示すASCII文字に、 2**7 ビットが付加されます。したがって文字列に含めることができるメタ文字のコードは1から255の範囲となり、メタ文字は通常のASCII文字のメタ修飾されたバージョンとなります。文字列内でのMETA処理の詳細については、文字列内へのキーボードイベントの配置を参照してください。

メタ文字の入力構文には‘\M-’を使用します。たとえば‘?\M-A’はM-Aを意味します。8進文字コード(以下参照)や、‘\C-’、その他の文字にたいする他の構文とともに‘\M-’を使用できます。したがって、M-Aは‘?\M-A’や‘?\M-\101’と記述できます。同様にC-M-bは‘?\M-\C-b’、‘?\C-\M-b’、‘?\M-\002’と記述することができます。


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

2.4.3.5 その他の文字修飾ビット

グラフィック文字(graphic character)のcaseは文字コードで示されます。たとえばASCIIでは、文字‘a’と文字‘A’は区別されます。しかしASCIIにはコントロール文字が大文字なのか小文字なのかを表現する方法がありません。コントロール文字がタイプされたときシフトキーが使用されたかを示すために、Emacsは 2**25 のビットを使用します。この区別はX端末や、その他の特別な端末を使用しているときだけ可能です。通常のテキスト端末は、これらの違いを報告しません。シフトをあらわすビットのためのLisp構文は‘\S-’です。したがって‘?\C-\S-o’や‘?\C-\S-O’は、Shift+Ctrl+o文字を表します。

Xウィンドウシステムは文字にセットするために、他にも3つ修飾ビット — ハイパー(hyper)スーパー(super)アルト(alt)を定義します。これらのビットにたいする構文は、‘\H-’、‘\s-’、‘\A-’です(これらのプレフィクスでは、caseは意味がある)。したがって‘?\H-\M-\A-x’はAlt-Hyper-Meta-xを表します(‘-’が後にない‘\s’はスペース文字を表すことに注意)。 数値としてはビット値2**22はアルト、2**23はスーパー、2**24はハイパーです。


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

2.4.4 シンボル型

GNU Emacs Lispでのシンボル(symbol)とは、名前をもつオブジェクトです。シンボル名は、そのシンボルのプリント表現としての役割があります。Lispの通常の使用では、1つのobarray(シンボルの作成とinternを参照)により、シンボル名は一意です — 2つのシンボルが同じ名前をもつことはありません。

シンボルは変数や関数名としての役割、プロパティーリストを保持する役割をもつことができます。データ構造内にそのようなシンボルが存在することが確実に認識できるように、他のすべてのLispオブジェクトから区別するためだけの役割をもつ場合もあります。与えられたコンテキストにおいて、通常はこれらのうちの1つの使用だけが意図されます。しかし3つすべての方法で、1つのシンボルを独立して使用することもできます。

名前がコロン(‘:’)で始まるシンボルはキーワードシンボル(keyword symbol)と呼ばれます。これらのシンボルは自動的に定数として振る舞い、通常は未知のシンボルといくつかの特定の候補を比較することだけに使用されます。変更不可な変数を参照してください。

シンボル名にはどんな文字でも含めることができます。ほとんどのシンボル名は英字、数字、‘-+=*/’などの区切り文字で記述されます。このような名前には特別な区切り文字は必要ありません。名前が数字のように見えない限り、名前にはどのような文字も使用できます(名前が数字のように見える場合は、名前の先頭に‘\’を記述して強制的にシンボルとして解釈させる)。文字‘_~!@$%^&:<>{}?’はあまり使用されませんが、これらも特別な句読点文字を必要としません。他の文字も、バックスラッシュでエスケープすることにより、シンボル名に含めることができます。しかし文字列内でのバックスラッシュの使用とは対照的に、シンボル名でのバックスラッシュは、バックスラッシュの後の1文字をエスケープするだけです。たとえば文字列内では、‘\t’はタブ文字を表します。しかしシンボル名の中では、‘\t’は英字‘t’をクォートするに過ぎません。名前にタブ文字をもつシンボルを記述するには、(バックスラッシュを前置した)実際のタブを使用しなければなりません。しかし、そのようなことを行なうことは稀です。

Common Lispに関する注意:Common Lispでは明示的にエスケープされない限り、小文字は常に大文字に“フォールド(folded)”される。Emacs Lispでは大文字と小文字は区別される。

以下はシンボル名の例です。4つ目の例の中の‘+’は、シンボルが数字として読み取られるのを防ぐためにエスケープされていることに注意してください。6つ目の例では、名前の残りの部分により数字としては不正なのでエスケープの必要はありません。

foo                 ; foo’という名前のシンボル
FOO                 ; foo’とは別の、‘FOO’という名前のシンボル
1+                  ; 1+’という名前のシンボル
                    ;   (整数の‘+1’ではない)
\+1                 ; +1’という名前のシンボル
                    ;   (判読しにくい名前)
\(*\ 1\ 2\)         ; (* 1 2)’という名前のシンボル(悪い名前)
+-*/_~!@$%^&=:<>{}  ; +-*/_~!@$%^&=:<>{}’という名前のシンボル
                    ;   これらの文字のエスケープは不要

シンボル名がプリント表現としての役割をもつというルールの例外として、‘##’があります。これは、名前が空文字列のinternされたシンボルのプリント表現です。さらに‘#:foo’は、internされていないfooという名前のシンボルにたいするプリント表現です(通常、Lispリーダーはすべてのシンボルをinternする。シンボルの作成とinternを参照されたい)。


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

2.4.5 シーケンス型

シーケンス(sequence)とは、要素の順序セットを表現するLispオブジェクトです。Emacs Lispには2種類のシーケンス — リスト(lists)配列(arrays)があります。

リストはもっとも一般的に使用されるシーケンスです。リストは任意の型の要素を保持でき、要素の追加と削除により簡単に長さを変更できます。リストについては、次のサブセクションを参照してください。

配列は固定長のシーケンスです。配列はさらに文字列(strings)、ベクター(vectors)、文字テーブル(char-tables)、ブールベクター(bool-vectors)に細分されます。ベクターは任意の型の要素を保持できますが、文字列の要素は文字でなければならず、ブールベクターの要素はtnilでなければなりません。文字テーブルはベクターと似ていますが、有効な文字によりインデックスづけされる点が異なります。文字列内の文字は、バッファー内の文字のようにテキストプロパティーをもつことができます(テキストのプロパティを参照)。しかしベクターはその要素が文字のときでも、テキストプロパティーをサポートしません。

リスト、文字列、およびその他の配列型も、重要な類似点を共有します。たとえば、それらはすべて長さlをもち、要素は0からl-1でインデックスづけされます。いくつかの関数はシーケンス関数と呼ばれ、これらは任意の種類のシーケンスを許容します。たとえば、関数lengthは、任意の種類のシーケンスの長さを報告します。シーケンス、配列、ベクターを参照してください。

シーケンスは読み取りにより常に新たに作成されるやめ、同じシーケンスを2回読み取るのは一般的に不可能です。シーケンスにたいする入力構文を2回読み取った場合には、内容が等しい2つのシーケンスを得ます。これには1つ例外があります。空リスト()は、常に同じオブジェクトnilを表します。


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

2.4.6 コンスセルとリスト型

コンスセル(cons cell)CARスロット、CDRスロットと呼ばれる2つのスロットから構成されるオブジェクトです。それぞれのスロットはには、任意のLispオブジェクトを保持できます。そのときCARスロットに保持されるオブジェクトが何であれ、わたしたちは“このコンスセルのCAR”のような言い方をします。これはCDRの場合も同様です。

リスト(list)はコンスセルの連続するシリーズで、各コンスセルのCDRスロットは次のコンスセル、または空リストを保持します。空リストは実際にはシンボルnilです。詳細については、リストを参照してください。ほとんどのコンスセルはリストの一部として使用されるので、わたしたちはコンスセルにより構成される任意の構造を、リスト構造(list structure)という用語で参照します。

Cプログラマーにたいする注意: Lispのリストはコンスセルにより構築されるリンクリスト(linked list)として機能する。Lispではポインターは暗黙的なので、コンスセルのスロットが値を“保持(hold)”するのか、それとも値を“指す(point)”のかは区別しない。

コンスセルはLispの中核なので、コンスセルではないオブジェクトにたいする用語もあります。これらのオブジェクトはアトム(atoms)と呼ばれます。

リストにたいする入力構文とプリント表現は同じで左カッコ、任意の数の要素、右カコから構成されます。以下はリストの例です:

(A 2 "A")            ; 3要素のリスト
()                   ; 要素がないリスト(空リスト)
nil                  ; 要素がないリスト(空リスト)
("A ()")             ; 1要素のリスト: 文字列"A ()"
(A ())               ; 2要素のリスト: Aと空リスト
(A nil)              ; 同上
((A B C))            ; 1要素のリスト
                     ;   (この要素は、3要素のリスト)

読み取りではカッコの内側はリストの要素になります。つまりコンスセルは各要素から作成されます。コンスセルのCARスロットは要素を保持し、CDRスロットはリスト内の次のコンスセル(このコンスセルはリスト内の次の要素をする)を参照します。最後のコンスセルのCDRスロットはnilを保持するようにセットされます。

CARCDRという名称はLispの歴史に由来します。オリジナルのLisp実装はIBM 704コンピューターで実行されていました。ワードを2つの部分、つまり“address”と呼ばれる部分と、“decrement”と呼ばれる部分に分割していて、その際CARはaddress部から内容を取り出す命令で、CDRはdecrement部から内容を取り出す命令でした。これとは対照的に“cons cells”は、これらを作成する関数consから命名されました。この関数は関数の目的、すなわちセルを作る(construction of cells)という目的から命名されました。


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

2.4.6.1 ボックスダイアグラムによるリストの描写

コンスセルを表現するドミノのような1対のボックスによる図で、リストを説明することができます(Lispリーダーがこのような図を読み取ることはできない。人間とコンピューターが理解できるテキスト表記と異なり、ボックス図は人間だけが理解できる)。この図は3要素のリスト(rose violet buttercup)を表したものです:

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

この図では、ボックスは任意のLispオブジェクトへの参照を保持できるスロットを表します。ボックスのペアーはコンスセルを表します。矢印はLispオブジェクト(アトム、または他のコンスセル)への参照を表します。

この例では、1番目のボックスは1番目のコンスセルで、それのCARrose(シンボル)を参照または保持します。2番目のボックスは1番目のコンスセルのCDRを保持し、次のボックスペアすなわち2番目のコンスセルを参照します。2番目のコンスセルのCARvioletで、CDRは3番目のコンスセルです。(最後の)3番目のコンスセルのCDRnilです。

同じリスト(rose violet buttercup)を、違うやり方で描いた別の図で表してみましょう:

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

要素がないリストは空リスト(empty list)で、これはシンボルnilと同じです。言い換えるとnilはシンボルであり、かつリストでもあります。

以下はリスト(A ())、または等価な(A nil)をボックスと矢印で描いたものです:

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

以下はもっと複雑な例です。これは1番目の要素が2要素のリストであるような、3要素のリスト((pine needles) oak maple)を表します:

    --- ---      --- ---      --- ---
   |   |   |--> |   |   |--> |   |   |--> nil
    --- ---      --- ---      --- ---
     |            |            |
     |            |            |
     |             --> oak      --> maple
     |
     |     --- ---      --- ---
      --> |   |   |--> |   |   |--> nil
           --- ---      --- ---
            |            |
            |            |
             --> pine     --> needles

同じリストを2番目のボックス表記で表すと、以下のようになります:

 --------------       --------------       --------------
| car   | cdr  |     | car   | cdr  |     | car   | cdr  |
|   o   |   o------->| oak   |   o------->| maple |  nil |
|   |   |      |     |       |      |     |       |      |
 -- | ---------       --------------       --------------
    |
    |
    |        --------------       ----------------
    |       | car   | cdr  |     | car     | cdr  |
     ------>| pine  |   o------->| needles |  nil |
            |       |      |     |         |      |
             --------------       ----------------

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

2.4.6.2 ドットペア表記

ドットペア表記(dotted pair notation)は、CARCDRが明示的に表されたコンスセルの一般的な構文です。この構文では(a . b)CARがオブジェクトaCDRがオブジェクトbという意味になります。CDRがリストである必要がないので、ドットペア表記はより一般的なリスト構文です。しかしリスト構文が機能するような場合には、より扱いにくくなります。ドットペア表記では、リスト‘(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)は無効です。なぜならこれは何も意味していないからです。何か意味があるとしても、violetのためにCDRがすでに使用されているコンスセルのCDRに、buttercupを置くということになります。

リスト(rose violet)(rose . (violet))と等価であり、以下のようになります:

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

同様に3要素のリスト(rose violet buttercup)は、(rose . (violet . (buttercup)))と等価です。 これは以下のようになります:

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

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

2.4.6.3 連想リスト型

連想リスト(association list)またはalistは、要素がコンスセルであるように特別に構成されたリストです。各要素においては、CARキー(key)で、CDR連想値(associated value)であると考えます(連想値がCDRCARに保存される場合もある)。リストの先頭への連想値の追加と削除は簡単なので、連想リストはスタック(stack)にしばしば使用されます。

たとえば、

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

これは変数alist-of-colorsに3要素のalistをセットします。最初の要素では、roseがキーでredが値になります。

alistとalist関数についての詳細な説明は連想リストを参照してください。(多くのキーの操作をより高速に行なう)テーブルを照合する他の手段についてはハッシュテーブルを参照してください。


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

2.4.7 配列型

配列(array)は、他のLispオブジェクトを保持または参照する任意の数のスロットから構成され、メモリーの連続ブロックに配列されます。配列の任意の要素へのアクセス時間は大体同じです。対照的にリストの要素にたいするアクセスは、リスト内でのその要素の位置に比例した時間を要します(リストの最後の要素にアクセスするにはリストの最初の要素にアクセスするより長い時間が必要)。

Emacsは文字列(strings)、ベクター(vectors)、ブールベクター(bool-vectors)、文字テーブル(char-tables)という4種の配列を定義します。

文字列は文字の配列であり、ベクターは任意のオブジェクトの配列です。ブールベクターはtnilだけを保持できます。この種の配列はシステムアーキテクチャー制限と利用可能なメモリーにしたがったもっとも大きいfixnumまでの任意の長さをもつことができます。文字テーブルは、任意の有効な文字コードによりインデックスづけされる疎な配列であり、任意のオブジェクトを保持することができます。

配列の最初の要素はインデックス0、2番目の要素はインデックス1、...となります。これは0基準(zero-origin)のインデックスづけと呼ばれます。たとえば、4要素の配列はインデックス0、1、2、3をもちます。利用できる最大のインデックス値は、配列の長さより1つ小さくなります。▼一度配列が作成されると、長さは固定されます。

Emacs Lispのすべての配列は、1次元です(他のほとんどのプログラミング言語は多次元配列をサポートするが、これらは必須ではない。ネストされた1次元配列により同じ効果を得ることが可能)。各種の配列は独自の入力構文をもちます。詳細は以降のセクションを参照してください。

配列型はシーケンス型のサブセットであり文字列型、ベクター型、ブールベクター型、文字テーブル型が含まれます。


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

2.4.8 文字列型

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

文字列を操作する関数については文字列と文字を参照してください。


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

2.4.8.1 文字列の構文

文字列にたいする入力構文は"like this"のようにダブルクォート、任意個数の文字、もう1つのダブルクォートから構成されます。文字列内にダブルクォートを含める場合は、それの前にバックスラッシュを記述します。したがって"\""は1つのダブルクォート文字だけを含む文字列です。同様にバックスラッシュを含める場合は、"this \\ is a single embedded backslash"のように、それの前にもう1つのバックスラッシュを記述します。

文字列にたいする入力構文では、改行(newline)は特別ではありません。ダブルクォートの間に改行を記述すれば、その改行は文字列内の文字となります。しかしエスケープされた改行 — 前に‘\’をともなう改行 — は文字列の一部とはなりません。同様にエスケープされたスペース‘\  も無視されます。

"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."

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

2.4.8.2 文字列内の非ASCII文字

Emacdの文字列内の非ASCII文字にたいしては2つのテキスト表現 — マルチバイト(multibyte)とユニバイト(unibyte)があります(テキストの表現方法を参照)。大まかに言うとユニバイト文字列にはraw(生)バイトが保存され、マルチバイト文字列には人間が読めるテキストが保存されます。ユニバイト文字列内の各文字はバイトであり、値は0から255となります。対照的にマルチバイト文字列内の各文字は、0から4194303の値をもつかもしれません(文字型を参照)。いずれも127より上の文字は非ASCIIです。

文字をリテラルとして記述することにより、文字列に非ASCII文字を含めることができます。マルチバイトのバッファーや文字列、あるいはマルチバイトとしてvisitされたファイル等、マルチバイトのソースから文字列定数を読み込む場合、Emacsは非ASCII文字をマルチバイト文字として読み取り、その文字列を自動的にマルチバイト文字列にします。ユニバイトのソースから文字列定数を読み込む場合、Emacsは非ASCII文字をユニバイト文字として読み取り、その文字列をユニバイト文字列にします。

マルチバイト文字列内にリテラルとして文字を記述するかわりに、エスケープシーケンスを使用して文字コードとして記述できます。エスケープシーケンスについての詳細は、一般的なエスケープ構文を参照してください。

文字列定数内でUnicodeスタイルのエスケープシーケンス‘\uNNNN’または‘\U00NNNNNN’を使用する場合、(たとえASCII文字であっても)Emacsは自動的に文字列をマルチバイトとみなします。

文字列定数内で16進エスケープシーケンス(‘\xn’)と8進エスケープシーケンス(‘\n’)を使用することもできます。しかし注意してください: 文字列定数が16進または8進のエスケープシーケンスを含み、それらのエスケープシーケンスすべてがユニバイト文字(256より小)を指定していて、その文字列内に他にリテラルの非ASCII文字またはUnicodeスタイルのエスケープシーケンスが存在しない場合、Emacsは自動的に文字列をユニバイト文字列とみなします。つまり文字列内のすべての非ASCII文字は8ビットのrawバイトとみなされます。

16進および8進のエスケープシーケンスでは、エスケープされた文字コードに可変個の数字が含まれるかもしれないので、それに続く文字で16進および8進として有効ではない最初の文字は、そのエスケープシーケンスを終了させます。文字列内の次の文字が16進または8進として解釈できる文字の場合は、‘\  (バックスラッシュとスペース)を記述して、エスケープシーケンスを終了できます。たとえば‘\xe0\ はgrave accentつきの‘a’という1文字を表します。文字列内の‘\  はバックスラッシュ改行と同様です。これは文字列内の文字とはなりませんが、先行する16進エスケープを終了します。


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

2.4.8.3 文字列内の非プリント文字

リテラル文字と同様に、文字列定数内でバックスラッシュによるエスケープシーケンスを使用できます(ただし文字定数を開始するクエスチョンマークは使用しない)。たとえば非プリント文字のタブとC-aを含む文字列は、"\t, \C-a"のように、それらの間にカンマとスペースを記述します。文字にたいする入力構文については文字型を参照してください。

しかしバックスラッシュによるエスケープシーケンスとともに記述できるすべての文字が、文字列内で有効というわけではありません。文字列が保持できるコントロール文字はASCIIコントロール文字だけです。ASCIIコントロール文字では、文字列のcaseは区別されません。

正確に言うと、文字列はメタ文字を保持できません。しかし文字列がキーシーケンスとして使用される場合には、文字列内でメタ修飾されたASCII文字を表現するための方法を提供する特別な慣習があります。文字列定数内でメタ文字を示すために‘\M-’構文を使用した場合、これは文字列内の文字の 2**7 のビットをセットします。その文字列がdefine-keyまたはlookup-keyで使用される場合、この数字コードは等価なメタ文字に変換されます。文字型を参照してください。

文字列はハイパー(hyper)、スーパー(super)、アルト(alt)で修飾された文字を保持できません。


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

2.4.8.4 文字列内のテキストプロパティ

文字列にはその文字自身に加えて、文字のプロパティーも保持することができます。これにより特別なことをしなくても、文字列とバッファーとの間でテキストをコピーするプログラムが、テキストプロパティーをコピーすることが可能になります。テキストプロパティーが何を意味するかについてはテキストのプロパティを参照してください。テキストプロパティーをもつ文字列は、特別な入力構文とプリント構文を使用します。

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

ここでproperty-dataは,3個でグループ化された0個以上の要素から構成されます:

beg end plist

要素begおよびendは整数で、文字列内のインデックスの範囲を指定します。plistはその範囲にたいするプロパティーリストです。たとえば、

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

これはテキスト内容が‘foo bar’で、最初の3文字はfaceプロパティーに値boldをもち、最後の3文字はfaceプロパティーに値italicをもつことを表します(4番目の文字にはテキストプロパティーはないので、プロパティーリストはnil。実際には範囲の中の指定されていない文字はデフォルトではプロパティーをもたないので、範囲のプロパティーリストをnilと指定する必要ない)。


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

2.4.9 ベクター型

ベクター(vector)は任意の型の要素からなる1次元の配列です。ベクター内の任意の要素へのアクセスに要す時間は一定です(リストの場合では要素へのアクセスに要す時間は、リストの先頭からその要素までの距離に比例する)。

ベクターのプリント表現は左角カッコ(left square bracket)、要素、右角カッコ(right square bracket)から構成されます。これは入力構文でもあります。数字や文字列と同様にベクターは評価において定数と判断されます。

[1 "two" (three)]      ; 3要素のベクター
     ⇒ [1 "two" (three)]

ベクターに作用する関数についてはベクターを参照してください。


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

2.4.10 文字テーブル型

文字テーブル(char-table)は任意の型の要素をもつ1次元の配列であり、文字コードによりインデックスづけされます。文字テーブルは、文字コードに情報を割り当てることを必要とする多くの処理を簡単にするための、特別な追加の機能をもちます — たとえば文字テーブルは継承する親、デフォルト値、特別な目的のために使用する余分なスロットをいくつかもつことができます。文字テーブルは文字セット全体にたいして1つの値を指定することもできます。

文字テーブルのプリント表現はベクターと似ていますが、最初に余分な‘#^’があります1

文字テーブルを操作する特別な関数については文字テーブルを参照してください。文字テーブルの使用には以下が含まれます:


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

2.4.11 ブールベクター型

ブールベクター(bool-vector)は、要素がtnilのいずれかでなければならない1次元の配列です。

ブールベクターのプリント表現は文字列と似ていますが、後に長さを記述した‘#&’で始まります。これに続く文字列定数は、ビットマップとして実際に内容を指定するブールベクターです — 文字列定数内のそれぞれの“文字”は8ビットを含み、これはブールベクターの次の8要素を指定します(1はt、0はnilです)。文字の最下位ビットブールベクターの最下位のインデックスに対応します。

(make-bool-vector 3 t)
     ⇒ #&3"^G"
(make-bool-vector 3 nil)
     ⇒ #&3"^@"

C-g’の2進コードは111、‘C-@’はコード0の文字なのでこの結果は理にかなっています。

長さが8の倍数でなければプリント表現には余分な要素が表示されますが、これらの余分な要素に意味はありません。たとえば以下の例では、最初の3ビットだけが使用されるので2つのブールベクターは等価です:

(equal #&3"\377" #&3"\007")
     ⇒ t

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

2.4.12 ハッシュテーブル型

ハッシュテーブルは非常に高速な照合テーブルの一種で、キーを対応する値にマップするalistと似ていますがより高速です。ハッシュテーブルのプリント表現では、以下のようにハッシュテーブルのプロパティーと内容を指定します:

(make-hash-table)
     ⇒ #s(hash-table size 65 test eql rehash-size 1.5
                             rehash-threshold 0.8125 data ())

ハッシュテーブルについての詳細はハッシュテーブルを参照してください。


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

2.4.13 関数型

他のプログラミング言語の関数と同様、Lisp関数は実行可能なコードです。他の言語と異なり、Lispの関数はLispオブジェクトでもあります。Lispのコンパイルされていない関数はラムダ式 — つまり1番目の要素がシンボルlambdaであるリストです(ラムダ式を参照)。

ほとんどのプログラミング言語では名前のない関数はありません。Lispでは関数に本質的な名前はありません。名前がなくてもラムダ式を関数として呼び出すことができます。これを強調するために、わたしたちはこれを無名関数(anonymous function)とも呼びます(無名関数を参照)。Lispの名前つき関数は関数セルに有効な関数がセットされた単なるシンボルです(関数の定義を参照)。

ほとんどの場合、関数はLispプログラム内のLisp式の名前が記述されたところで呼び出されます。しかし実行時に関数オブジェクトを構築または取得してから、プリミティブ関数funcallおよびapplyにより呼び出すことができます。関数の呼び出しを参照してください。


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

2.4.14 マクロ型

Lispマクロ(Lisp macro)はLisp言語を拡張するユーザー定義の構成です。これはオブジェクトとしてではなく関数のように表現されますが、引数の渡し方の意味が異なります。Lispマクロの形式はリストです。これは最初の要素がmacroで、CDRがLisp関数オブジェクト(lambdaシンボルを含む)であるようなリストです。

Lispマクロオブジェクトは通常、ビルトインのdefmacro関数で定義されますが、macroで始まる任意のリストもEmacsにとってはマクロです。マクロを記述する方法の説明はマクロを参照してください。

警告: Lispマクロとキーボードマクロ(キーボードマクロを参照)は完全に別の物である。修飾なしで“マクロ”という単語を使用したときは、キーボードマクロではなくLispマクロのことを指す。


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

2.4.15 プリミティブ関数型

プリミティブ関数(primitive function)とは、Cプログラミング言語で記述されたLispから呼び出せる関数です。プリミティブ関数はsubrsビルトイン関数(built-in functions)とも呼ばれます(単語“subr”は“サブルーチン(subroutine)”が由来)。ほとんどのプリミティブ関数ハ、呼び出されたときニすべての引数を評価します。すべての引数を評価しないプリミティブ関数はスペシャルフォーム(special form)と呼ばれます(スペシャルフォームを参照)。

呼び出す側からすれば、その関数がプリミティブ関数かどうかは問題になりません。しかしプリミティブ関数をLispで記述された関数で再定義した場合に問題になります。理由はそのプリミティブ関数がCコードから直接呼び出されているかもしれないからです。Lispから再定義した関数を呼び出すと新しい定義を使用するでしょうが、Cコードから呼び出すとビルトインの定義が使用されるでしょう。したがって、プリミティブ関数の再定義はしないでください

関数(function)という用語で、LispやCで記述されたすべてのEmacs関数を参照します。Lispで記述された関数についての情報は関数型を参照してください。

プリミティブ関数に入力構文はなく、サブルーチン名とともにハッシュ表記でプリントします。

(symbol-function 'car)          ; そのシンボルの関数セルに
                                ;     アクセスする
     ⇒ #<subr car>
(subrp (symbol-function 'car))  ; これはプリミティブ関数?
     ⇒ t                ;    そのとおり

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

2.4.16 バイトコード関数型

バイトコード関数オブジェクト(byte-code function objects)は、Lispコードをバイトコンパイルすることにより生成されます(バイトコンパイルを参照)。バイトコード関数オブジェクトは、内部的にはベクターによく似ています。しかしバイトコード関数オブジェクトが関数呼び出しのように見える場合、評価プロセスによりこのデータ型は特別に処理されます。バイトコード関数オブジェクトを参照してください。

バイトコード関数オブジェクトのプリント表現と入力構文はベクターのものと似ていますが、開き角カッコ‘[’の前に‘#’があります。


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

2.4.17 レコード型

レコード(record)vectorと似ていますが、最初の要素はtype-ofでリターンされる型を保持するために使用されます。レコードの主要目的はプログラマーがEmacsのビルトインではない新たな型を作成することを可能にすることです。

レコードに作用する関数についてはレコードを参照してください。


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

2.4.18 型記述子

型記述子(type descriptor)は型に関する情報を保持するrecordです。レコードの1スロット目には型を命名するシンボルでなければならず、type-ofrecordオブジェクトの型をリターンするためにこれに依存しています。他の型記述子スロットをEmacsは使用しません。これらをLisp拡張が使用するのは自由です。

cl-structure-classのインスタンスはすべて型記述子の例です。


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

2.4.19 autoload型

autoloadオブジェクト(autoload object)は、最初の要素がシンボルautoloadのリストです。これはシンボルの関数定義として保存され、実際の定義にたいする代替としての役割をもちます。autoloadオブジェクトは、必要な時にロードされるLispコードファイルの中で実際の定義を見つけることができることを宣言します。これにはファイル名と、それに加えて実際の定義についての他のいくつかの情報が含まれます。

ファイルのロード後、そのシンボルはautoloadオブジェクトではない新しい関数定義をもつはずです。新しい定義は、最初からそこにあったかのように呼び出されます。ユーザーの観点からは関数呼び出しは期待された動作、つまりロードされたファイル内の関数定義を使用します。

autoloadオブジェクトは通常、シンボルの関数セルにオブジェクトを保存する関数autoloadにより作成されます。詳細はautoloadを参照してください。


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

2.4.20 ファイナライザー型

ファイナライザーオブジェクト(finalizer object)は、オブジェクトがもはや必要なくなった後のLispコードのクリーンアップを助けます。ファイナライザーは、Lisp関数オブジェクトを保持します。ガーベージコレクションのオアス後にファイナライザーオブジェクトが到達不能になったとき、Emacsはそのファイナライザーに関連付けられた関数オブジェクトを呼び出します。ファイナライザーの到達可否の判定時、もしかしてファイナライザーオブジェクト自身が参照を離さないのではないかと心配することなくファイナライザーを使用できるように、Emacsはファイナラーオブジェト自身からの参照は勘定しません。

ファイナラーザー内でのエラーは*Messages*にプリントされます。その関数が失敗しても、Emacsは与えられたファイナライザーオブジェクトに関連付けられた関数を正確に1回実行します。

Function: make-finalizer function

functionを実行するファイナライザーを作成する。functionはガーベージコレクション後、リターンされたファイナライザーオブジェクトが到達不能になったときに実行される。そのファイナライザーオブジェクトがファイナライザーオブジェクトからの参照を通じてのみ到達可能なら、functionの実行是非の判断時の目的にたいして、それは到達可能とみなされない。functionはファイナライザーオブジェクトごとに1回実行される。


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

2.5 編集用の型

前セクションの型は一般的なプログラミング目的のために使用され、これらの型のほとんどはLisp方言のほとんどで一般的です。Emacs Lispは編集に関する目的のために、いくつかの追加のデータ型を提供します。


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

2.5.1 バッファー型

バッファー(buffer)とは、編集されるテキストを保持するオブジェクトです(バッファーを参照)。ほとんどのバッファーはディスクファイル(ファイルを参照)の内容を保持するので編集できますが、他の目的のために使用されるものもいくつかあります。ほとんどのバッファーはユーザーにより閲覧されることも意図しているので、いつかはウィンドウ内(ウィンドウを参照)に表示されます。しかしバッファーはウィンドウに表示される必要はありません。バッファーはそれぞれ、ポイント(point)と呼ばれる位置指定をもちます(ポジションを参照)。ほとんどの編集コマンドは、カレントバッファー内のポイントに隣接する内容を処理します。常に1つのバッファーがカレントバッファー(current buffer)です。

バッファーの内容は文字列によく似ていますが、バッファーはEmacs Lispの文字列と同じようには使用されず、利用可能な操作は異なります。文字列にテキストを挿入するためには部分文字列の結合が必要で、結果は完全に新しい文字列オブジェクトなのるのにたいして、バッファーでは既存のバッファーに効率的にテキストを挿入してバッファーの内容を変更できます。

標準的なEmacs関数の多くは、カレントバッファー内の文字を操作したりテストするためのものです。このマニュアルはこれらの関数の説明のために、1つのチャプターを設けています(テキストを参照)。

他のデータ構造のいくつかは、各バッファーに関連付けられています:

ローカルキーマップと変数リストは、グローバルなバインディングや値を個別にオーバーライドするためのエントリーを含みます。これらは実際にプログラムを変更することなく、異なるバッファーでプログラムの振る舞いをカスタマイズするために使用されます。

バッファーはインダイレクト(indirect: 間接) — つまり他のバッファーとテキストを共有するがそれぞれ別に表示する — かもしれません。インダイレクトバッファーを参照してください。

バッファーに入力構文はありません。バッファーはバッファー名を含むハッシュ表記でプリントされます。

(current-buffer)
     ⇒ #<buffer objects-ja.texi>

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

2.5.2 マーカー型

マーカー(marker)は特定のバッファー内の位置を表します。したがってマーカーには2つの内容 — 1つはバッファー、もう1つは位置 — をもちます。バッファーのテキストの変更では、マーカーが常にバッファー内の同じ2つの文字の間に位置することを確実にするために、必要に応じて自動的に位置の値が再配置されます。

マーカーは入力構文をもちません。マーカーはカレントの文字位置とそのバッファー名を与える、ハッシュ表記でプリントされます。

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

マーカーのテスト、作成、コピー、移動の方法についての情報はマーカーを参照してください。


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

2.5.3 ウィンドウ型

ウィンドウ(window)はEmacsがバッファーを表示するために使用する端末スクリーンの部分を記述します。すべてのウィンドウは関連付けられた1つのバッファーをもち、バッファーの内容はそのウィンドウに表示されます。それとは対照的に、あるバッファーは1つのウィンドウに表示されるか表示されないか、それとも複数のウィンドウに表示されるかもしれません。

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

スクリーン上でウィンドウはフレームにグループ化されます。ウィンドウはそれぞれ、ただ1つのフレームだけに属します。フレーム型を参照してください。

ウィンドウは入力構文をもちません。ウィンドウはウィンドウ番号と表示されているバッファー名を与える、ハッシュ表記でプリントされます。与えられたウィンドウに表示されるバッファーは頻繁に変更されるかもしれないので、一意にウィンドウを識別するためにウィンドウ番号が存在します。

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

ウィンドウに作用する関数の説明はウィンドウを参照してください。


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

2.5.4 フレーム型

フレーム(frame)とは1つ以上のEmacsウィンドウを含むスクリーン領域です。スクリーン領域を参照するためにEmacsが使用するLispオブジェクトを指す場合にも“フレーム”という用語を使用します。

フレームは入力構文をもちません。フレームはフレームのタイトルとメモリー内のアドレス(フレームを一意に識別するのに有用)を与えるハッシュ表記でプリントされます。

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

フレームに作用する関数の説明はフレームを参照してください。


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

2.5.5 端末型

端末(terminal)は1つ以上のEmacsフレーム(フレーム型を参照)を表示する能力があるデバイスです。

端末は入力構文をもちません。端末はその端末の順序番号とTTYデバイスファイル名を与える、ハッシュ表記でプリントされます。

(get-device-terminal nil)
     ⇒ #<terminal 1 on /dev/tty>

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

2.5.6 ウィンドウ構成型

ウィンドウ構成(window configuration)はフレーム内のウィンドウの位置とサイズ、内容についての情報を保持します。これにより後で同じウィンドウ配置を再作成できます。

ウィンドウ構成は入力構文をもちません。ウィンドウ構成のプリント表現は‘#<window-configuration>’のようになります。ウィンドウ構成に関連するいくつかの関数の説明はウィンドウの構成を参照してください。


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

2.5.7 フレーム構成型

フレーム構成(frame configuration)はすべてのフレーム内のウィンドウの位置とサイズ、内容についての情報を保持します。これは基本型ではありません — 実際のところ、これはCARframe-configurationCDRがalistであるようなリストです。それぞれのalist要素は、その要素のCARに示される1つのフレームを記述します。

フレーム構成に関連するいくつかの関数の説明はフレーム構成を参照してください。


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

2.5.8 プロセス型

プロセス(process)という単語は、通常は実行中のプログラムを意味します。Emacs自身はこの種のプロセス内で実行されます。しかしEmacs Lispでは、プロセスとはEmacsプロセスにより作成されたサブプロセスを表すLispオブジェクトです。シェル、GDB、ftp、コンパイラーなどのプログラムは、Emacsのサブプロセスとして実行されEmacsの能力を拡張します。さらに操作を行なうために、EmacsサブプロセスはEmacsからテキスト入力を受け取り、テキスト出力をEmacsにリターンします。Emacsがサブプロセスにシグナルを送ることもできます。

プロセスオブジェクトは入力構文をもちません。プロセスオブジェクトはプロセス名を与えるハッシュ表記でプリントされます。

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

プロセスの作成、削除、プロセスに関する情報のリターン、入力やシグナルの送信、出力の受信を行なう関数についての情報はプロセスを参照してください。


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

2.5.9 スレッド型

Emacsでのスレッド(thread)とはEmacs Lispの実行スレッドとは別のスレッドを表します。これは自身のLispプログラムを実行して、自身のカレントバッファーを所有して、そのスレッドにロックされたサブプロセスをもつことができます(サブプロセスの出力を受け取ることができるのはそのスレッドのみ)。スレッドを参照してください。

スレッドオブジェクトは入力構文をもちません。スレッドオブジェクトは(名前を与えられていれば)スレッド名を与えるハッシュ表記かメモリー内のアドレスでプリントされます。

(all-threads)
    ⇒ (#<thread 0176fc40>)

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

2.5.10 ミューテックス型

ミューテックス(mutex)とはスレッド間で同期をとるためにスレッドが所有と非所有することができる排他ロックです。ミューテックスを参照してください。

ミューテックスオブジェクトは入力構文をもちません。プロセスオブジェクトは(名前を与えられていれば)ミューテックス名を与えるハッシュ表記かメモリー内のアドレスでプリントされます。

(make-mutex "my-mutex")
    ⇒ #<mutex my-mutex>
(make-mutex)
    ⇒ #<mutex 01c7e4e0>

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

2.5.11 状態変数型

状態変数(condition variable)はミューテックスがサポートするよりも複雑な非同期スレッドのためのデバイスです。スレッドは別のスレッドが状態を通知したときに再開するように状態変数を待機することができます。

状態変数オブジェクトは入力構文をもちません。プロセスオブジェクトは(名前が与えられていれば)状態変数の名前を与えるハッシュ表記かメモリー内のアドレスでプリントされます。

(make-condition-variable (make-mutex))
    ⇒ #<condvar 01c45ae8>

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

2.5.12 ストリーム型

ストリーム(stream)とは、文字のソースまたはシンクとして — つまり入力として文字を供給したり、出力として文字を受け入れるために使用できるオブジェクトです。多くの異なるタイプ — マーカー、バッファー、文字列、関数をこの方法で使用できます。ほとんどの場合、入力ストリーム(文字列ソース)はキーボード、バッファー、ファイルから文字を受け取り、出力ストリーム(文字シンク)は文字を*Help*バッファーのようなバッファーやエコーエリアに文字を送ります。

オブジェクトnilは、他の意味に加えてストリームとして使用されることがあります。nilは変数standard-inputstandard-outputの値を表します。オブジェクトtも入力としてミニバッファー(ミニバッファーを参照)、出力としてエコーエリア(エコーエリアを参照)の使用を指定するストリームになります。

ストリームは特別なプリント表現や入力構文をもたず、それが何であれそれらの基本型としてプリントされます。

パース関数およびプリント関数を含む、ストリームに関連した関数の説明はLispオブジェクトの読み取りとプリントを参照してください。


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

2.5.13 キーマップ型

キーマップ(keymap)はユーザーがタイプした文字をコマンドにマップします。このマップはユーザーのコマンド入力が実行される方法を制御します。キーマップは、実際にはCARがシンボルkeymapであるようなリストです。

キーマップの作成、プレフィクスキーの処理、ローカルキーマップやグローバルキーマップ、キーバインドの変更についての情報はキーマップを参照してください。


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

2.5.14 オーバーレイ型

オーバーレイ(overlay)はバッファーの一部に適用するプロパティーを指定します。それぞれのオーバーレイはバッファーの指定された範囲に適用され、プロパティーリスト(プロパティー名と値が交互に記述された要素のリスト)を含みます。オーバーレイプロパティーは、バッファーの指定された一部を、一時的に異なるスタイルで表示するために使用されます。オーバーレイは入力構文をもたず、バッファー名と範囲の位置を与えるハッシュ表記でプリントされます。

オーバーレイを作成したり使用する方法についての情報はオーバーレイを参照してください。


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

2.5.15 フォント型

fontはグラフィカルな端末上のテキストを表示する方法を指定します。実際には異なる3つのフォント型 — フォントオブジェクト(font objects)フォントスペック(font specs)フォントエンティティー(font entities) — が存在します。これらは入力構文をもちません。これらのプリント構文は‘#<font-object>’、‘#<font-spec>’、‘#<font-entity>’のようになります。これらのLispオブジェクトの説明は低レベルのフォント表現を参照してください。


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

2.6 循環オブジェクトの読み取り構文

複雑なLispオブジェクトでの共有された構造や循環する構造を表すために、リーダー構成‘#n=’と‘#n#’を使用することができます。

後でオブジェクトを参照するには、オブジェクトの前で#n=を使用します。その後で、他の場所にある同じオブジェクトを参照するために、#n#を使用することができます。ここでnは任意の整数です。たとえば以下は、1番目の要素が3番目の要素にも繰り替えされるリストを作成する方法です:

(#1=(a) b #1#)

これは、以下のような通常の構文とは異なります

((a) b (a))

これは1番目の要素と3番目の要素がそっくりなリストですが、これらは同じLispオブジェクトではありません。以下で違いを見ることができます:

(prog1 nil
  (setq x '(#1=(a) b #1#)))
(eq (nth 0 x) (nth 2 x))
     ⇒ t
(setq x '((a) b (a)))
(eq (nth 0 x) (nth 2 x))
     ⇒ nil

“要素”として自身を含むような循環する構造を作成するために、同じ構文を使用できます。以下は例です:

#1=(a #1#)

これは2番目の要素がそのリスト自身であるリストを作成します。これが実際にうまくいくのか、以下で確認できます:

(prog1 nil
  (setq x '#1=(a #1#)))
(eq x (cadr x))
     ⇒ t

変数print-circleを非nil値にバインドした場合、Lispプリンターは、循環および共有されるLispオブジェクトを記録するこの構文を生成することができます。出力に影響する変数を参照してください。


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

2.7 型のための述語

関数が呼び出されたとき、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にputする
         (setq list (cons x list)))
        ((listp x)
         ;; Xがリストならその要素をLISTに追加
         (setq list (append x list)))
        (t
         ;; シンボルとリストだけを処理する
         (error "Invalid argument %s in add-on" x))))

以下のテーブルは事前定義された型述語(アルファベット順)と、さらに情報を得るためのリファレンスです。

atom

atomを参照のこと。

arrayp

arraypを参照のこと。

bignump

floatpを参照のこと。

bool-vector-p

bool-vector-pを参照のこと。

booleanp

booleanpを参照のこと。

bufferp

bufferpを参照のこと。

byte-code-function-p

byte-code-function-pを参照のこと。

case-table-p

case-table-pを参照のこと。

char-or-string-p

char-or-string-pを参照のこと。

char-table-p

char-table-pを参照のこと。

commandp

commandpを参照のこと。

condition-variable-p

condition-variable-pを参照のこと。

consp

conspを参照のこと。

custom-variable-p

custom-variable-pを参照のこと。

fixnump

floatpを参照のこと。

floatp

floatpを参照のこと。

fontp

低レベルのフォント表現を参照のこと。

frame-configuration-p

frame-configuration-pを参照のこと。

frame-live-p

frame-live-pを参照のこと。

framep

framepを参照のこと。

functionp

functionpを参照のこと。

hash-table-p

hash-table-pを参照のこと。

integer-or-marker-p

integer-or-marker-pを参照のこと。

integerp

integerpを参照のこと。

keymapp

keymappを参照のこと。

keywordp

変更不可な変数を参照のこと。

listp

listpを参照のこと。

markerp

markerpを参照のこと。

mutexp

mutexpを参照のこと。

nlistp

nlistpを参照のこと。

number-or-marker-p

number-or-marker-pを参照のこと。

numberp

numberpを参照のこと。

overlayp

overlaypを参照のこと。

processp

processpを参照のこと。

recordp

recordpを参照のこと。

sequencep

sequencepを参照のこと。

string-or-null-p

string-or-null-pを参照のこと。

stringp

stringpを参照のこと。

subrp

subrpを参照のこと。

symbolp

symbolpを参照のこと。

syntax-table-p

syntax-table-pを参照のこと。

threadp

threadpを参照のこと。

vectorp

vectorpを参照のこと。

wholenump

wholenumpを参照のこと。

window-configuration-p

window-configuration-pを参照のこと。

window-live-p

window-live-pを参照のこと。

windowp

windowpを参照のこと。

あるオブジェクトがどの型かチェックするもっとも一般的な方法は、関数type-ofの呼び出しです。オブジェクトは、ただ1つだけの基本型に属することを思い出してください。type-ofは、それがどの型かを告げます(Lispのデータ型を参照)。しかしtype-ofは基本型以外の型については何も知りません。ほとんどの場合では、type-ofより型述語を使用するほうが便利でしょう。

Function: type-of object

この関数はobjectの基本型を名前とするシンボルをリターンする。リターン値はシンボルbool-vectorbufferchar-tablecompiled-functioncondition-variableconsfinalizerfloatfont-entityfont-objectfont-specframehash-tableintegermarkermutexoverlayprocessstringsubrsymbolthreadvectorwindowwindow-configurationのいずれか。ただしobjectがレコードなら最初のスロットで指定された型をリターンする。レコードを参照のこと。

(type-of 1)
     ⇒ integer
(type-of 'nil)
     ⇒ symbol
(type-of '())    ; ()nil
     ⇒ symbol
(type-of '(x))
     ⇒ cons
(type-of (record 'foo))
     ⇒ foo

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

2.8 同等性のための述語

ここでは2つのオブジェクトの同一性をテストする関数を説明します。(たとえば文字列などの)特定の型のオブジェクト同士で内容の同一性をテストするには、別の関数を使用します。これらの述語にたいしては、そのデータ型を説明する適切なチャプターを参照してください。

Function: eq object1 object2

この関数はobject1object2が同じオブジェクトならt、それ以外はnilをリターンする。

object1object2が同じ名前をもつシンボルなら、通常は同じオブジェクトだが例外もある。シンボルの作成とinternを参照のこと。他の非数値型(リストやベクター、文字列などの)にたいしては、同じ内容(または要素)の2つの引数が両者eqである必要はない。これらが同じオブジェクトの場合だけeqであり、その場合には一方の内容を変更するともう一方の内容にも同じ変更が反映される。

object1object2異なるタイプや値をもつ数値なら同じオブジェクトではなく、eqnilをリターンする。同じ値をもつfixnumなら同じオブジェクトであり、eqtをリターンする。別個に計算されてたまたま同じ値をもち、かつ非fixnumタイプの同じ数値型なら、それらは同じかもしれないし違うかもしれず、Lispインタープリターが作成したオブジェクトが1つか2つかに依存してeqtnilをリターンする。

(eq 'foo 'foo)
     ⇒ t

(eq ?A ?A)
     ⇒ t

(eq 3.0 3.0)
     ⇒ t または nil
;; 浮動小数にたいするeqではオブジェクト同じかもしれず違うかもしれない

(eq (make-string 3 ?A) (make-string 3 ?A))
     ⇒ nil

(eq "asdf" "asdf")
     ⇒ t または nil
;; 文字列コンテンツにたいするeqではオブジェクト同じかもしれず違うかもしれない

(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関数はinternされていないシンボルをリターンする。これはLisp式内でその名前を記述したシンボルとは区別される。同じ名前の異なるシンボルはeqではない。シンボルの作成とinternを参照のこと。

(eq (make-symbol "foo") 'foo)
     ⇒ nil

Emacs Lispバイトコンパイラーはリテラル文字列のような等価なリテラルオブジェクトを同一オブジェクトにたいする参照に落し込む(collapse into)かもしれない。バイトコンパイルされたコードはそのようなオブジェクトをeqで比較するだろうが、そうでないコードは異なるという効果がある。したがってコードではオブジェクトのリテラルコンテンツがeqか否かではなく、以下に説明するequalのような関数でオブジェクトの関数を使用すること。同様にコードではリテラルオブジェクトを変更(たとえばリテラル文字列へのテキストプロパティのput)しないこと。バイトコンパイラーがそれらの落し込みを行っていたら、同一コンテンツをもつ別のリテラルオブジェクトに影響があるかもしれない。

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

文字列の比較はcaseを区別するがテキストプロパティーは考慮しない — これは文字列内の文字だけを比較する。テキストのプロパティを参照のこと。テキストプロパティーも比較する場合には、equal-including-propertiesを使用すること。技術的な理由によりユニバイト文字列とマルチバイト文字列は、それらが同じ文字コードのシーケンスを含み、それらのコードがすべて0から127(ASCII)の場合に限りequalとなる(テキストの表現方法を参照)。

(equal "asdf" "ASDF")
     ⇒ nil

しかし2つの別のバッファーは、それらのテキスト内容が同じでもequalと判断されることはない。

equalでは等価性は再帰的に定義されています。たとえば2つのコンスセルxyを与えると、(equal x y)は、以下の式の両方がtをリターンする場合だけtをリターンします:

(equal (car x) (car y))
(equal (cdr x) (cdr y))

したがって循環リストの比較はエラーとなるような深い再帰を引き起こすかもしれず、(equal a b)tをリターンするにも関わらず(equal b a)はエラーをシグナルするといった直感に反する結果となることがあります。

Function: equal-including-properties object1 object2

この関数はすべてのケースにおいてequalと同様に振る舞うが、2つの文字列がequalになるためには、それらが同じテキストプロパティーをもつ必要がある。

(equal "asdf" (propertize "asdf" 'asdf t))
     ⇒ t
(equal-including-properties "asdf"
                            (propertize "asdf" 'asdf t))
     ⇒ nil

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

2.9 可変性

変更されるべきではないLispオブジェクトがいくつかあります。たとえばLisp式"aaa"では文字列を生成しますが、そのコンテンツを変更するべきではありません。いくつかのオブジェクトは変更できません。たとえばある数値を計算して新たな数値を作成できたとしても、Lispは既存の数値を変更する操作を提供しません。

その他のLispオブジェクトは副作用をともなう破壊的な操作を通じて安全に値を変更可能なmutable(可変)オブジェクトです。たとえばマーカーを別のポイントを指すマーカーに移動することにより、既存のマーカーを変更することができます。

数値は変更不可でマーカーはすべてmutableだとしても、mutableと非mutableのメンバーをもつタイプがいくつかあります。これらのタイプにはコンス、ベクター、文字列が含まれます。たとえば"cons"(symbol-name 'cons)は変更するべきではない文字列を生成しますが、(copy-sequence "cons")(make-string 3 ?a)は後からasetを呼び出すことを通じて変更可能なmutable文字列を生成します。

mutableオブジェクトは評価される式の一部となったときにmutableであることを止めます。たとえば:

(let* ((x (list 0.5))
       (y (eval (list 'quote x))))
  (setcar x 1.5) ;; プログラムはこれを行うべきではない
  y)

作成時にリスト(0.5)がmutableでも、それはevalに与えられるのでsetcarを通じて変更するべきではありません。変更するべきではないオブジェクトが後からmutableになることは決してないので逆はあり得ません。

変更するべきではないオブジェクトの変更をプログラムが試みた際の動作は未定義です。Lispインタープリターがエラーをシグナルするかもしれず、クラッシュしたり他の方法で予測不能な振る舞いを引き起こすかもしれません2

プログラムの一部として類似した定数が出現する際には、既存の定数やそのコンポーネントの再利用によってLispが時間やスペースを節約できるかもしれません。たとえば(eq "abc" "abc")はインタープリターが文字列リテラル"abc"の1つのインスタンスを作成したらt、2つのインスタンスを作成したらnilをリターンします。したがってこの最適化使用の有無に関わらず機能するようにLispプログラムを記述する必要があります。


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

3 数値

GNU Emacsは2つの数値データ型 — 整数(integers)浮動小数点数(floating-point numbers)をサポートします。整数は-3、0、7、13、511などの整数です。浮動小数点数は-4.5、0.0、2.71828などの小数部をもちます。これらは指数記数法でも表現できます — ‘1.5e2’は‘150.0’と同じです。ここで‘e2’は10の2乗を表し、それに1.5を乗じるという意味です。整数計算は正確です。浮動小数点数の計算では数値は固定された精度をもつので、しばしば丸め誤差(rounding errors)が発生します。


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

3.1 整数の基礎

Lispリーダーは、10進数字のシーケンス(オプションで最初の符号記号と最後のピリオドをともなう)として整数を読み取ります。

 1               ; 整数1
 1.              ; 整数1
+1               ; これも整数1
-1               ; 整数-1
 0               ; 整数0
-0               ; 整数0

10以外の基数をもつ整数の構文は‘#’、基数表示(radix indication)、その後の1つ以上の数字から構成されます。基数表示は2進数(binary)は‘b’、8進数(octal)は‘o’、16進数(hex)は‘x’、基数radixにたいしては‘radixr’になります。したがって‘#binteger’は2進数、‘#radixrinteger’は基数radixintegerを読み取ります。radixの値として可能な値は2から36であり、最初のradix文字は‘0’–‘9’および‘A’–‘Z’から採択されます。英文字のcase(大文字小文字)は無視されて、最初の符号と最後のピリオドはありません。たとえば:

#b101100 ⇒ 44
#o54 ⇒ 44
#x2c ⇒ 44
#24r1k ⇒ 44

整数にたいして処理を行なうさまざまな関数、特にビット演算(整数にたいするビット演算を参照)を理解するためには、数を2進形式で見ることが助けになることがよくあります。

10進整数の5は2進数では以下のようになります:

…000101

(省略記号‘’は概念的に先頭ビットにマッチする無限個数のビットを意味する。ここでは無限個の0ビット。後の例でも‘’表記を使用する。)

整数の-1は以下のようになります:

…111111

-1はすべて1で表現されます(2の補数表記と呼ばれる)。

-1から4を減じることで負の整数-5が得られます。10進の整数4は2進では100です。したがって-5は以下のようになります:

…111011

このチャプターで説明する多くの関数は、数字の位置として引数にマーカー(マーカーを参照)を受け取ります。そのような関数にたいする実際の引数は数字かマーカーなので、わたしたちはこれらの引数にnumber-or-markerという名前を与えることがあります。引数の値がマーカーならマーカーの位置が使用され、マーカーのバッファーは無視されます。

Emacs Lispでは、テキスト文字は整数により表現されます。0から(max-char)までの整数は、有効な文字として判断されます。文字コードを参照してください。

Emacs Lispの整数はマシンのワードサイズに制限されません。しかしその背後にはfixnumsと呼ばれる小さい整数と、bignumsと呼ばれる大きい整数という2種類の整数が存在します。Emacs Lispコードは通常は整数がfixnumかbignumのいずれであるかに依存するべきではありませんが、Emacsの古いバージョンではfixnumだけがサポートされており、未だにfixnumだけを受け取るEmacs関数がいくつかあり、古いEmacs Lispコードがbignumを受け取ると問題が起こるかもしれません。たとえば古いEmacs Lispコードはeqで整数にたいする数値の等価性を安全に比較できましたが、bignumの登場により整数の比較にはeql=のような等価性にたいする述語を使うことが必要になりました。

bignumの値の範囲は主メモリー量、bignumの指数の表現に使用されるワードサイズのようなマシン特性、およびinteger-width変数により制限されます。これらの制限は通常はfixnumにたいする制限よりは寛大です。bignumが数値的にfixnumと等しくなることはありません。Emacsはfixnum範囲内の整数を、bignumではなく常にfixnumとして表現します。

fixnumの値の範囲はマシンに依存します。最小の範囲は-536,870,912から536,870,911(30ビット長の -2**29 から 2**29 - 1) ですが、多くのマシンはより広い範囲を提供します。

Variable: most-positive-fixnum

この変数の値はEmacs Lispが扱える“小さい”整数の最大値。典型的な値は32ビットでは 2**29 - 1 、64ビットでは 2**61 - 1 。

Variable: most-negative-fixnum

この変数の値はEmacs Lispが扱える数値的に最小の“小さい”整数。これは負の整数。典型的な値は32ビットでは -2**29 、64ビットでは -2**61、 。

Variable: integer-width

この変数の値は大きな整数えお計算時にEmacsが範囲エラー(range error)をシグナルするかどうかを制御する負ではない整数。絶対値が 2**n, (nはこの変数の値)が小さい整数は範囲エラーをシグナルしない。大きい整数を簡単に作成できればエラーがシグナルされない場合もあるが、通常は大きな整数の作成を試みると範囲エラーをシグナルする。この変数に大きな数値を設定すると、巨大な整数の計算にコストを要する可能性がある。


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

3.2 浮動小数点数の基礎

浮動小数点数は整数以外の数値の表現に有用です。浮動小数点数の範囲は使用中のシンでのCのデータ型doubleと同じ範囲です。EmacsがサポートするすべてのコンピューターではIEEEの64ビット浮動小数フォーマットであり、これはIEEE Std 754-2019で標準化されたもので、David Goldbergの論文“What Every Computer Scientist Should Know About Floating-Point Arithmetic”で更に議論されています。モダンなプラットフォームでは浮動小数処理はIEEE-754標準に厳密にしたがいますが、特に32ビットX86のような陳腐化したプラットフォームでは丸めは常に正しい訳ではありません。

浮動小数点数にたいする入力構文は、小数点と指数のどちらか1つ、または両方が必要とします。オプションの符号(‘+’か‘-’)は、その数字と指数の前に記述します。たとえば‘1500.0’、‘+15e2’、‘15.0e+2’、‘+1500000e-3’、‘.15e4’は値が1500の浮動小数点数を記述する5つの方法です。これらはすべて等価です。Common Lispと同様、Emacs Lispは浮動小数点数の小数点の後に少なくとも1つの数字を必要とします。‘1500.’は整数であって浮動小数点数ではありません。

Emacs Lispは=のような数学的な比較に関して、-0.0を通常の0と数学的に同じものとして扱います。これは、(他の処理がこれらを区別するとしても-0.00.0は数学的に等しいとする)IEEE浮動小数点数規格にしたがっています。

IEEE浮動小数点数規格は浮動小数点数として、正の無限大と負の無限大をサポートします。この規格はNaNまたは“not a number(数字ではない)”と呼ばれる値クラスも提供します。正しい答えが存在しないような場合に、数学関数はこのような値をリターンします。たとえば(/ 0.0 0.0)はNaNをリターンします。数値的にNaNはたとえ自身と比較してもすべての値にたいして数値的にイコールになることはありません。NaNは符号と仮数をもち、非数学関数は符号と仮数が一致すれば2つのNaNを等しいものと扱います。NaNの仮数は文字列表現の数字のようにマシン依存です。

NaNと符号つき0が関係する際にはeqlequalsxhash-eqlsxhash-equalgethashのような非数学関数はそれらが数学的にイコールかではなく、値が区別できるかどうかを判断します。たとえばxyが同じNaNなら数値比較を使用する(= x y)nilをリターンするのにたいして(equal x y)tをリターンして、反対に(= 0.0 -0.0)tをリターンするのにたいして(equal 0.0 -0.0)nilをリターンします。

以下は、これらの特別な浮動小数点数にたいする入力構文です:

infinity

1.0e+INF’と‘-1.0e+INF

not-a-number

0.0e+NaN’と‘-0.0e+NaN

以下の関数は浮動小数点数を扱うために特化したものです:

Function: isnan x

この述語は浮動小数引数がNaNならt、それ以外はnilをリターンする。

Function: frexp x

この関数はコンスセル(s . e)をリターンする。ここでseは、浮動小数点数の仮数(浮動小数点数を2の指数表現したときの仮数)と指数である。

xが有限ならsは0.5以上1.0未満の浮動小数点数、eは整数で、 x = s * 2**eとなる。 xが0または無限ならsxと等しくなる。xがNaNならsもNaN。xが0ならeは0。

Function: ldexp s e

数値の仮数sと整数の指数eを与えられると、この関数は浮動小数点数 s * 2**eをリターンする。

Function: copysign x1 x2

この関数はx2の符号をx1の値にコピーして結果をリターンする。x1x2は浮動小数でなければならない。

Function: logb x

この関数はxの2進指数をリターンする。より正確にはxが有限かつ非0なら|x|の2を底とする対数を整数に切り下げた値。xが0または無限なら値は無限大。xがNaなら値はNaN。

(logb 10)
     ⇒ 3
(logb 10.0e20)
     ⇒ 69
(logb 0)
     ⇒ -1.0e+INF

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

3.3 数値のための述語

このセクションの関数は数値や、特定の数値型にたいしてテストを行ないます。関数integerpfloatpは、引数として任意のLispオブジェクト型をとることができます(でなければ、あまり使用する機会ない)。しかし述語zeropは引数として数値を要求します。マーカーのための述語integer-or-marker-pnumber-or-marker-pも参照してください。

Function: bignump object

この述語は引数が大きい整数かどうかをテストしてもしそうならt、それ以外はnilをリターンする。小さい整数とは異なり大きい整数はeqでなくても=eqlになり得る。

Function: fixnump object

この述語は引数が小さい整数かどうかをテストしてもしそうならt、それ以外はnilをリターンする。小さい整数はeqで比較できる。

Function: floatp object

この述語は引数が浮動小数かどうかをテストしてもしそうならt、それ以外はnilをリターンする。

Function: integerp object

この述語は引数が整数かどうかをテストしてもしそうならt、それ以外はnilをリターンする。

Function: numberp object

この述語は引数が数(整数か浮動小数)かどうかをテストしてもしそうならt、それ以外はnilをリターンする。

Function: natnump object

この述語は引数が正の整数かどうかをテストしてもしそうならt、それ以外はnilをリターンする(名前は“natural numberl: 自然数”が由来)。0は整数と判断される。

wholenumpnatnumpのシノニム。

Function: zerop number

この述語は引数が0かどうかをテストしてもしそうならt、それ以外はnilをリターンする。引数は数でなければならない。

(zerop x)(= x 0)と等価。


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

3.4 数値の比較

数値にたいして数学的な等価性をテストするには通常はeqeqlequalのような非数値的な比較述語のかわりに=を使用するべきです。異なる浮動小数点オブジェクトと大きい整数オブジェクトを数値的に等しくすることができます。これらの比較にeqを使用した場合にはそれらが同一のオブジェクトかどうかを、eqlequalを使用した場合にはそれらの値が区別不能かどうかをテストすることになります。対照的に=は数値比較を使用して、非数値的な比較がnilをリターンするような場合にtをリターンしたり、その逆もあり得ます。浮動小数点数の基礎を参照してください。

Emacs Lispでは2つのfixnumが数値的に等しければ同一のLispオブジェクトです。つまりfixnumではeq=と同じです。値が未知のfixnumの比較にeqを使用する方が便利な場合があります。なぜなら未知の値が数でない場合でもeqはエラーを報告しないからです。これは任意のタイプの引数を受け付けます。対照的に引数が数でもマーカーでもなければ=はエラーをシグナルします。しかし整数の比較においてさえ、使用できる場合には=を使用するのがよいプログラミング習慣です。

数の比較において、2つの数が同じデータ型(どちらも整数か浮動小数)では、同じ値の場合は等しい数として扱うeqlequalのほうが便利なときもあります。対照的に=は整数と浮動小数点数を等しい数と扱うことができます。同等性のための述語を参照してください。

他の欠点もあります。浮動小数演算は正確ではないので、浮動小数値を比較するのが悪いアイデアとなるときがよくあります。通常は近似的に等しいことをテストするほうがよいでしょう。以下はこれを行なう関数です:

(defvar fuzz-factor 1.0e-6)
(defun approx-equal (x y)
  (or (= x y)
      (< (/ (abs (- x y))
            (max (abs x) (abs y)))
         fuzz-factor)))
Function: = number-or-marker &rest number-or-markers

この関数はすべての引数が数値的に等しいかどうかをテストしてもしそうならt、それ以外はnilをリターンする。

Function: eql value1 value2

この関数はeqと同様に振る舞うが引数が両方とも数のときを除く。これは数を型と数値的な値により比較するので(eql 1.0 1)nilをリターンするが、(eql 1.0 1.0)(eql 1 1)tをリターンする。これは小さい整数と同様に大きい整数の比較に使用できる。

Function: /= number-or-marker1 number-or-marker2

この関数は引数が数値的に等しいかどうかをテストして、もし異なる場合はt、等しい場合はnilをリターンする。

Function: < number-or-marker &rest number-or-markers

この関数は、各引数それぞれを後の引数より小さいかどうかをテストしてもしそうならt、それ以外はnilをリターンする。

Function: <= number-or-marker &rest number-or-markers

この関数は、各引数それぞれが後の引数以下かどうかをテストしてもしそうならt、それ以外はnilをリターンする。

Function: > number-or-marker &rest number-or-markers

この関数は、各引数それぞれが後の引数より大きいかどうかをテストしてもしそうならt、それ以外はnilをリターンする。

Function: >= number-or-marker &rest number-or-markers

この関数は、各引数それぞれが後の引数以上かどうかをテストしてもしそうならt、それ以外はnilをリターンする。

Function: max number-or-marker &rest numbers-or-markers

この関数は最大の引数をリターンする。

(max 20)
     ⇒ 20
(max 1 2.5)
     ⇒ 2.5
(max 1 3 2.5)
     ⇒ 3
Function: min number-or-marker &rest numbers-or-markers

この関数は最小の引数をリターンする。

(min -4 1)
     ⇒ -4
Function: abs number

この関数はnumberの絶対値をリターンする。


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

3.5 数値の変換

整数を浮動少数の変換には関数floatを使用します。

Function: float number

これは浮動小数点数に変換されたnumberをリターンする。すでにnumberが浮動小数点数ならfloatはそれを変更せずにリターンする。

浮動小数点数を整数に変換する関数が4つあります。これらは浮動小数点数を丸める方法が異なります。これらはすべて引数number、およびオプション引数としてdivisorを受け取ります。引数は両方とも整数か浮動小数点数です。divisornilのこともあります。divisornilまたは省略された場合、これらの関数はnumberを整数に変換するか、それが既に整数の場合は変更せずにリターンします。divisorが非nilなら、これらの関数はnumberdivisorで除して結果を整数に変換します。divisorが(整数か浮動小数かに関わらず)0の場合、Emacsはarith-errorエラーをシグナルします。

Function: truncate number &optional divisor

これは0に向かって丸めることにより整数に変換したnumberをリターンする。

(truncate 1.2)
     ⇒ 1
(truncate 1.7)
     ⇒ 1
(truncate -1.2)
     ⇒ -1
(truncate -1.7)
     ⇒ -1
Function: floor number &optional divisor

これは下方(負の無限大に向かって)に丸めることにより整数に変換したnumberをリターンする。

divisorが指定された場合には、modに相当する種類の除算演算を使用して下方に丸めを行う。

(floor 1.2)
     ⇒ 1
(floor 1.7)
     ⇒ 1
(floor -1.2)
     ⇒ -2
(floor -1.7)
     ⇒ -2
(floor 5.99 3)
     ⇒ 1
Function: ceiling number &optional divisor

これは上方(正の無限大に向かって)に丸めることにより整数に変換したnumberをリターンする。

(ceiling 1.2)
     ⇒ 2
(ceiling 1.7)
     ⇒ 2
(ceiling -1.2)
     ⇒ -1
(ceiling -1.7)
     ⇒ -1
Function: round number &optional divisor

これはもっとも近い整数に向かって丸めることにより、整数に変換したnumberをリターンする。2つの整数から等距離にある値の丸めでは、偶数の整数をリターンする。

(round 1.2)
     ⇒ 1
(round 1.7)
     ⇒ 2
(round -1.2)
     ⇒ -1
(round -1.7)
     ⇒ -2

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

3.6 算術演算

Emacs Lispは伝統的な4つの算術演算(加減乗除)、同様に剰余とmodulusの関数、および1の加算と減算を行う関数を提供します。%を除き、これらの各関数は引き数として整数か浮動小数を受け取り、浮動小数の引数がある場合は浮動小数点数をリターンします。

Function: 1+ number-or-marker

この関数はnumber-or-marker + 1をリターンする。例えば、

(setq foo 4)
     ⇒ 4
(1+ foo)
     ⇒ 5

この関数はCの演算子++とは異なり、変数をインクリメントしない。この関数は和を計算するだけである。したがって以下を続けて評価すると、

foo
     ⇒ 4

変数をインクリメントしたい場合は、以下のようにsetqを使用しなければならない:

(setq foo (1+ foo))
     ⇒ 5
Function: 1- number-or-marker

この関数はnumber-or-marker - 1をリターンする。

Function: + &rest numbers-or-markers

この関数は引数すべてを加算する。引数を与えないと+は0をリターンする。

(+)
     ⇒ 0
(+ 1)
     ⇒ 1
(+ 1 2 3 4)
     ⇒ 10
Function: - &optional number-or-marker &rest more-numbers-or-markers

-関数は2つの目的 — 符号反転と減算 — をもつ。-に1つの引数を与えると、値は引数の符号を反転したものになる。複数の引数の場合は、number-or-markerからmore-numbers-or-markersまでの各値を蓄積的に減算する。引数がなければ結果は0。

(- 10 1 2 3 4)
     ⇒ 0
(- 10)
     ⇒ -10
(-)
     ⇒ 0
Function: * &rest numbers-or-markers

この関数はすべての引数を乗じて積をリターンする。引数がなかれば*は1をリターンする。

(*)
     ⇒ 1
(* 1)
     ⇒ 1
(* 1 2 3 4)
     ⇒ 24
Function: / number &rest divisors

divisorsが1つ以上ならこの関数はdivisors内の除数で順にnumberを除して、その商をリターンする。divisorsがなければ、この関数は1/number、つまりnumberの逆数をリターンする。各引数には数かマーカーを指定できる。

すべての引数が整数なら、結果は各除算の後に商を0へ向かって丸めることにより得られる整数となる。

(/ 6 2)
     ⇒ 3
(/ 5 2)
     ⇒ 2
(/ 5.0 2)
     ⇒ 2.5
(/ 5 2.0)
     ⇒ 2.5
(/ 5.0 2.0)
     ⇒ 2.5
(/ 4.0)
     ⇒ 0.25
(/ 4)
     ⇒ 0
(/ 25 3 2)
     ⇒ 4
(/ -17 6)
     ⇒ -2

整数を整数0で除するとEmacsはarith-errorエラー(エラーを参照)をシグナルする。浮動小数点数の除算では、非0の数を0で除することで正の無限大または負の無限大を得る(浮動小数点数の基礎を参照)。

Function: % dividend divisor

この関数はdividenddivisorで除した後、その剰余を整数でリターンする。引数は整数かマーカーでなければならない。

任意の2つの整数dividenddivisorにたいして、

(+ (% dividend divisor)
   (* (/ dividend divisor) divisor))

は、divisorが非0なら常にdividendと等しくなる。

(% 9 4)
     ⇒ 1
(% -9 4)
     ⇒ -1
(% 9 -4)
     ⇒ 1
(% -9 -4)
     ⇒ -1
Function: mod dividend divisor

この関数はdividenddivisorにたいするmodulo、言い換えるとdividenddivisorで除した後の剰余(ただし符号はdivisorと同じ)をリターンする。引数は数かマーカーでなければならない。

%とは異なりmodは浮動小数の引数を許す。これは商を整数に下方(負の無限大に向かって)へ丸めて剰余を計算するのにこの商を使用する。

moddivisorが0のとき、両方の引数が整数ならarith-errorエラーをシグナルし、それ以外はNaNをリターンする。

(mod 9 4)
     ⇒ 1
(mod -9 4)
     ⇒ 3
(mod 9 -4)
     ⇒ -3
(mod -9 -4)
     ⇒ -1
(mod 5.5 2.5)
     ⇒ .5

任意の2つの数dividenddivisorにたいして、

(+ (mod dividend divisor)
   (* (floor dividend divisor) divisor))

は常にdividendになる(ただし引数のどちらかが浮動小数なら、丸め誤差の範囲内で等しく、かつdividendが整数でdivisorが0ならarith-errorとなる)。floorについては、数値の変換を参照のこと。


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

3.7 丸め処理

関数ffloorfceilingfroundftruncateは浮動小数の引数をとり、値が近くの整数であるような浮動少数をリターンします。ffloorは一番近い下方の整数、fceilingは一番近い上方の整数、ftruncateは0に向かう方向で一番近い整数、froundは一番近い整数をリターンします。

Function: ffloor float

この関数はfloatを次に小さい整数値に丸めて、その値を浮動小数点数としてリターンする。

Function: fceiling float

この関数はfloatを次に大きい整数値に丸めて、その値を浮動小数点数としてリターンする。

Function: ftruncate float

この関数はfloatを0方向の整数値に丸めて、その値を浮動小数点数としてリターンする。

Function: fround float

この関数はfloatを一番近い整数値に丸めて、その値を浮動小数点数としてリターンする。2つの整数値との距離が等しい値にたいする丸めでは、偶数の整数をリターンする。


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

3.8 整数にたいするビット演算

コンピューターの中では、整数はビット(bit: 0か1の数字)のシーケンスである2進数で表されます。ビットシーケンスは概念的には最上位ビットがすべて0か1であるような左側に無限なシ0ケンスです。ビット演算はそのようなシーケンスの中の個々のビットに作用します。たとえばシフト(shifting)はシーケンス全体を1つ以上左または右に移動して、移動されたのと同じパターンを再現します。

Emacs Lispのビット演算は整数だけに適用されます。

Function: ash integer1 count

ash (算術シフト(arithmetic shift))は、integer1の中のビット位置を左にcountシフトする。countが負なら右にシフトする。左シフトでは右側に0が挿入されて、右シフトでは最右ビットが破棄される。整数処理として考えると、ashinteger1を 2**count 乗じてから下方、負の無限大に向かって丸めることにより結果を変換する。

以下はビットパターンを1ビット左にシフトしてから右にシフトする例。この例で2進数パターンの下位ビットだけを示している。先行ビットは表示されている上位ビットにすべて一致する。確認できるように1ビットの左シフトは2を乗じて、右シフトは2で除してから負の無限大方向に丸められる。

(ash 7 1) ⇒ 14
;; 10進の7は10進の14になる
…000111
     ⇒
…001110

(ash 7 -1) ⇒ 3
…000111
     ⇒
…000011

(ash -7 1) ⇒ -14
…111001
     ⇒
…110010

(ash -7 -1) ⇒ -4
…111001
     ⇒
…111100

以下は2ビット左にシフトしてから右に2ビットシフトする例:

                  ;         2進数値
(ash 5 2)         ;   5  =  …000101
     ⇒ 20         ;      =  …010100
(ash -5 2)        ;  -5  =  …111011
     ⇒ -20        ;      =  …101100
(ash 5 -2)
     ⇒ 1          ;      =  …000001
(ash -5 -2)
     ⇒ -2         ;      =  …111110
Function: lsh integer1 count

lshlogical shiftの略で、integer1のビットを左にcountシフトする。countが負ならinteger1はfixnumか正のbignumのいずれかでなければならず、lshはシフト前に負のfixnumをmost-negative-fixnumで2回減算してあたかも符号なしであるかのように非負の結果を生成する。この奇妙な振る舞いはEmacsがfixnumsだけをサポートしていた頃の振る舞いであり、現在ではashがより良い選択である。

integer1count1がいずれも負の場合を除いてlshashのように振る舞うので、以下の例ではこれらの例外ケースに焦点をあてている。これらの例は30ビットのfixnumsを想定している。

                 ;      2進数値
(ash -7 -1)      ; -7 = …111111111111111111111111111001
     ⇒ -4        ;    = …111111111111111111111111111100
(lsh -7 -1)
     ⇒ 536870908 ;    = …011111111111111111111111111100
(ash -5 -2)      ; -5 = …111111111111111111111111111011
     ⇒ -2        ;    = …111111111111111111111111111110
(lsh -5 -2)
     ⇒ 268435454 ;    = …001111111111111111111111111110
Function: logand &rest ints-or-markers

この関数は引数のビットのANDをリターンする。すべての引数のn番目のビットが1の場合に限り、結果のn番目のビットが1となる。

たとえば13と12では、4ビット2進数を使用すると1101と1100のビットANDは1100を生成する。この2進数ではいずれも左の2ビットがセット(つまり1)されているので、リターンされる値の左2ビットがセットされる。しかし右の2ビットにたいしては少なくとも1つの引数でそのビットが0なので、リターンされる値の右2ビットは0になる。

したがって、

(logand 13 12)
     ⇒ 12

logandに何も引数も渡さなければ、値-1がリターンされる。-1を2進数で表すとすべてのビットが1なので、-1はlogandにたいする単位元(identity element)である。

                   ;        2進数値

(logand 14 13)     ; 14  =  …001110
                   ; 13  =  …001101
     ⇒ 12         ; 12  =  …001100

(logand 14 13 4)   ; 14  =  …001110
                   ; 13  =  …001101
                   ;  4  =  …000100
     ⇒ 4          ;  4  =  …000100

(logand)
     ⇒ -1         ; -1  =  …111111
Function: logior &rest ints-or-markers

この関数は、引数のビット単位の包含的ORをリターンする。少なくとも1つの引数でn番目のビットが1なら、結果のn番目のビットが1になる。引数を与えなければ、結果はこの処理にたいする単位元である0となる。logiorに渡す引数が1つだけならその引数がリターンされる。

                   ;        2進数値

(logior 12 5)      ; 12  =  …001100
                   ;  5  =  …000101
     ⇒ 13         ; 13  =  …001101

(logior 12 5 7)    ; 12  =  …001100
                   ;  5  =  …000101
                   ;  7  =  …000111
     ⇒ 15         ; 15  =  …001111
Function: logxor &rest ints-or-markers

この関数は、引数のビット単位の排他的ORをリターンする。n番目のビットが1であるような引数の数が奇数個の場合のみ、結果のn番目のビットが1となる。引数を与えなければ、結果はこの処理の単位元である0となる。logxorに渡す引数が1つだけならその引数がリターンされる。

                   ;        2進数値

(logxor 12 5)      ; 12  =  …001100
                   ;  5  =  …000101
     ⇒ 9          ;  9  =  …001001

(logxor 12 5 7)    ; 12  =  …001100
                   ;  5  =  …000101
                   ;  7  =  …000111
     ⇒ 14         ; 14  =  …001110
Function: lognot integer

この関数は引数のビット単位の補数(bitwise complement)をリターンする。integern番目のビットが0の場合に限り、結果のn番目のビットが1になり、その逆も成り立つ。結果は-1 - integerと等価。

(lognot 5)
     ⇒ -6
;;  5  =  …000101
;; becomes
;; -6  =  …111010
Function: logcount integer

この関数はintegerハミング重み (Hamming weight: integerの2進数表現での1の個数)をリターンする。integerが負なら、その2の補数の2進数表現での0ビットの個数をリターンする。結果は常に非負となる。

(logcount 43)     ;  43 = …000101011
     ⇒ 4
(logcount -43)    ; -43 = …111010101
     ⇒ 3

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

3.9 標準的な数学関数

以下の数学的関数は、引数として整数と同様に浮動小数点数も受け入れます。

Function: sin arg
Function: cos arg
Function: tan arg

これらは三角関数であり、引数argはラジアン単位。

Function: asin arg

(asin arg)の値は、sinの値がargとなるような -pi/2 から pi/2 (両端を含む)の数である。argが範囲外([-1, 1]の外)なら、asinはNaNをリターンする。

Function: acos arg

(acos arg)の値は、cosの値がargとなるような、0から pi (両端を含む)の数である。argが範囲外([-1, 1]の外)ならacosはNaNをリターンする。

Function: atan y &optional x

(atan y)の値は、tanの値がyとなるような、 -pi/2 から pi/2 (両端を含まず)の数である。オプションの第2引数xが与えられると、(atan y x)の値はベクトル[x, y]X軸が成す角度のラジアン値となる。

Function: exp arg

これは指数関数である。この関数はeの指数argをリターンする。

Function: log arg &optional base

この関数は底をbaseとするargの対数をリターンする。baseを指定しなければ、自然底(natural base)eが使用される。argbaseが負なら、logはNaNをリターンする。

Function: expt x y

この関数はxyを乗じてリターンする。引数が両方とも整数でyが非負なら結果は整数になる。この場合オーバーフローはエラーをシグナルするので注意。xが有限の負数でyが有限の非整数なら、exptはNaNをリターンする。

Function: sqrt arg

これはargの平方根をリターンする。argが有限で0より小さければ、sqrtはNaNをリターンする。

加えて、Emacsは以下の数学的な定数を定義します:

Variable: float-e

自然対数e(2.71828…)

Variable: float-pi

円周率pi(3.14159…)


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

3.10 乱数

決定論的なコンピュータープログラムでは真の乱数を生成することはできません。しかしほとんどの目的には、疑似乱数(pseudo-random numbers)で充分です。一連の疑似乱数は決定論的な手法により生成されます。真の乱数ではありませんが、それらにはランダム列を模する特別な性質があります。たとえば疑似ランダム系では、すべての可能な値は均等に発生します。

疑似乱数はシード値(seed value)から生成されます。与えられた任意のシードから開始することにより、random関数は常に同じ数列を生成します。デフォルトでは、Emacsは開始時に乱数シードを初期化することにより、それぞれのEmacsの実行において、randomの値シーケンスは(ほとんど確実に)異なります。

再現可能な乱数シーケンスが欲しい場合もあります。たとえば乱数シーケンスに依存するプログラムをデバッグする場合、プログラムの各実行において同じ挙動を得ることが助けになります。再現可能なシーケンスを作成するには、(random "")を実行します。これは特定のEmacsの実行可能ファイルにたいして、シードに定数値をセットします(しかしこの実行可能ファイルは、その他のEmacsビルドと異なるものになるであろう)。シード値として、他のさまざまな文字列を使用することができます。

Function: random &optional limit

この関数は疑似乱数の整数をリターンする。繰り返し呼び出すと一連の疑似乱数の整数をリターンする。

limitが正のfixnumなら、値は負ではないlimit未満の値から選択される。それ以外なら値はLispで表現可能な任意のfixnum(most-negative-fixnumからmost-positive-fixnumの間の任意の整数)となるだろう(整数の基礎を参照)。

limittなら、あたかもEmacsが再起動されたかのように、通常はシステムのエントロピーから新たなシードが選択されることを意味する。エントロピープールを欠くシステムでは、カレント時刻のような若干揮発性が低い乱数からシードが選択される。

limitが文字列なら、その文字列定数にもとづいた新しいシードを選択することを意味する。


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

4 文字列と文字

Emacs Lispの文字列は、文字列の順序列(ordered sequence)を含む配列です。文字列はシンボル、バッファー、ファイルの名前に使用されます。その他にもユーザーにたいしてメッセージを送ったりバッファー間でコピーする文字列を保持したり等、多くの目的に使用されます。文字列は特に重要なので、Emacs Lispは特別には文字列を操作するために多くの関数があります。Emacs Lispプログラムでは個々の文字より文字列を多用します。

キーボードの文字イベントの文字列にたいする特別な考慮は、文字列内へのキーボードイベントの配置を参照してください。


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

4.1 文字列と文字の基礎

文字(character)とは、テキスト内の1つの文字を表すLispオブジェクトです。Emacs Lispでは文字は単なる整数です。ある整数が文字か文字でないかを区別するのは、それが使用される方法だけです。Emacsでの文字表現についての詳細は文字コードを参照してください。

文字列(string)とは固定された文字シーケンスです。これは配列(array)と呼ばれるシーケンス型であり、配列長が固定で一度作成したら変更できないことを意味します(シーケンス、配列、ベクターを参照)。Cとは異なり、Emacs Lispの文字列は文字コードを判断することにより終端されません

文字列は配列であるということは同様にシーケンスでもあるので、シーケンス、配列、ベクターにドキュメントされている一般的な配列関数やシーケンス関数で文字列を処理できます。たとえば関数arefを使用して文字列内の特定の文字にアクセスしたり変更することができます(配列を操作する関数を参照)。

Emacs文字列での非ASCIIにたいすテキスト表現は2つ — ユニバイト(unibyte)とマルチバイト(multibyte)があります。ほとんどのLispプログラミングでは、これら2つの表現を気にする必要はありません。詳細はテキストの表現方法を参照してください。

キーシーケンスがユニバイト文字列で表されることがあります。ユニバイト文字列がキーシーケンスの場合、範囲128から255までの文字列要素は範囲128から255の文字コードではなく、メタ文字(これは非常に大きな整数である)を表します。文字列はハイパー(hyper)、スーパー(super)、アルト(alt)で修飾された文字を保持できません。文字列はASCIIコントロール文字を保持できますが、それは他のコントロール文字です。文字列はASCIIコントロール文字のcaseを区別できません。そのような文字をシーケンスに保存したい場合は、文字列ではなくベクターを使用しなければなりません。キーボード入力文字についての情報は文字型を参照してください。

文字列は正規表現を保持するために便利です。string-match (正規表現の検索を参照)を使用して、文字列にたいして正規表現をマッチすることもできます。関数match-string (単純なマッチデータへのアクセスを参照)とreplace-match (マッチしたテキストの置換を参照)は、文字列にたいして正規表現をマッチした後に、文字列を分解・変更するのに便利です。

バッファーのように、文字列は文字列内の文字自身とその文字にたいするテキストプロパティーを含みます。テキストのプロパティを参照してください。文字列からバッファーや他の文字列にテキストをコピーする、すべてのLispプリミティブ(Lisp primitives)はコピーされる文字のプロパティーもコピーします。

文字列の表示やバッファーにコピーする関数についての情報はテキストを参照してください。文字または文字列の構文についての情報は、文字型文字列型を参照してください。異なるテキスト表現間で変換したり、文字コードのエンコードやデコードを行う関数についてはASCII文字を参照してください。ディスプレイ上の文字列幅の計算にlength使用するべきではないことにも注意してください。かわりにstring-widthを使用してください(表示されるテキストのサイズを参照)。


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

4.2 文字列のための述語

一般的なシーケンスや配列にたいする述語についての情報は、シーケンス、配列、ベクター配列を参照してください。

Function: stringp object

この関数はobjectが文字列ならt、それ以外はnilをリターンする。

Function: string-or-null-p object

この関数はobjectが文字列かnilならt、それ以外はnilをリターンする。

Function: char-or-string-p object

この関数はobjectが文字列か文字(たとえば整数)ならt、それ以外はnilをリターンする。


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

4.3 文字列の作成

以下の関数は新たに文字列を作成したり、文字列同士の結合による文字列の作成や、文字列の一部から文字列を作成する関数です。

Function: make-string count character &optional multibyte

この関数はcharactercount回繰り返すことにより作成された文字列をリターンする。countが負ならエラーをシグナルする。

(make-string 5 ?x)
     ⇒ "xxxxx"
(make-string 0 ?x)
     ⇒ ""

characterASCII文字なら、結果は通常はユニバイト文字列になる。しかしオプション引数multibyteが非nilなら、この関数はかわりにマルチバイト文字列を生成する。これは結果を後で非ASCII文字列と結合したり、結果の中のいくつかの文字を非ASCII文字で置換する必要がある際に有用。

この関数に対応する他の関数にはmake-vector (ベクターを参照)やmake-list (コンスセルおよびリストの構築を参照)が含まれる。

Function: string &rest characters

この関数は文字charactersを含む文字列をリターンする。

(string ?a ?b ?c)
     ⇒ "abc"
Function: substring string &optional start end

この関数はstringから、インデックスstartの文字(その文字を含む)とendの文字(その文字は含まない)の間の範囲の文字で構成される、新しい文字列をリターンする。文字列の最初の文字はインデックス0。引数が1つなら、この関数は単にstringをコピーする。

(substring "abcdefg" 0 3)
     ⇒ "abc"

上記の例では‘a’のインデックスは0、‘b’のインデックスは1、‘c’のインデックスは2となる。インデックス3 — この文字列の4番目の文字 — は、コピーされる部分文字列の文字位置までをマークする。したがって文字列"abcdefg"から‘abc’がコピーされる。

負の数は文字列の最後から数えることを意味するので、-1は文字列の最後の文字のインデックスである。たとえば:

(substring "abcdefg" -3 -1)
     ⇒ "ef"

この例では‘e’のインデックスは-3、‘f’のインデックスは-2、‘g’のインデックスは-1。つまり‘e’と‘f’が含まれ、‘g’は含まれない。

endnilを使用した場合、それは文字列の長さを意味する。したがって、

(substring "abcdefg" -3 nil)
     ⇒ "efg"

引数endを省略した場合、それはnilを指定したのと同じである。(substring string 0)stringのすべてをコピーしてリターンする。

(substring "abcdefg" 0)
     ⇒ "abcdefg"

しかしこの目的のためにはcopy-sequenceを推奨する(シーケンスを参照)。

stringからコピーされた文字がテキストプロパティーをもつなら、そのプロパティーは新しい文字列へもコピーされる。テキストのプロパティを参照のこと。

substringの最初の引数にはベクターも指定できる。たとえば:

(substring [a b (c) "d"] 1 3)
     ⇒ [b (c)]

startが整数でない、またはendが整数でもnilでもななければ、wrong-type-argumentエラーがシグナルされる。startendの後の文字を指す、またはstringにたいして範囲外の整数をいずれかに指定すると、args-out-of-rangeエラーがシグナルされる。

この関数に対応するのはbuffer-substring (バッファーのコンテンツを調べるを参照)で、これはカレントバッファー内のテキストの一部を含む文字列をリターンする。文字列の先頭はインデックス0だが、バッファーの先頭はインデックス1である。

Function: substring-no-properties string &optional start end

これはsubstringと同じように機能するが、値のすべてのテキストプロパティーを破棄する。startを省略したりnilを指定することができ、その場合は0と等価だる。したがって(substring-no-properties string)は、すべてのテキストプロパティーが削除されたstringのコピーをリターンする。

Function: concat &rest sequences

この関数は渡された引数内の文字からなる文字列をリターンする(もしあればテキストプロパティーも)。引数には文字列、数のリスト、数のベクターを指定できる。引数は変更されない。concatに引数を指定しなければ空文字列をリターンする。

(concat "abc" "-def")
     ⇒ "abc-def"
(concat "abc" (list 120 121) [122])
     ⇒ "abcxyz"
;; nilhあ空のシーケンス。
(concat "abc" nil "-def")
     ⇒ "abc-def"
(concat "The " "quick brown " "fox.")
     ⇒ "The quick brown fox."
(concat)
     ⇒ ""

この関数は常に新たな文字列の割り当てを行う訳ではない。呼び出し側は結果が新たな文字列であること、もしくは既存の文字列にたいしてeqであることに依存しないよう推奨する。

特にリターン値を変更すると誤って別の文字列を変更したり、プログラム内の定数文字列の変更や、エラーをraiseすることさえあり得る。安全に変更できる文字列を取得するには、結果にcopy-sequenceを使用すること。

他の結合関数(concatenation functions)についての情報は関数のマッピングmapconcatベクターのための関数vconcatコンスセルおよびリストの構築appendを参照のこと。シェルコマンドで使用される文字列の中に、個々のコマンドライン引数を結合するには、combine-and-quote-stringsを参照されたい。

Function: split-string string &optional separators omit-nulls trim

この関数は正規表現separators(正規表現を参照)にもとづいて、stringを部分文字列に分解する。separatorsにたいする各マッチは分割位置を定義する。分割位置の間にある部分文字列をリストにまとめてリターンする。

separatorsnil (か省略)ならデフォルトはsplit-string-default-separatorsの値となり、関数はomit-nullstであるかのように振る舞う。

omit-nullsnil(または省略)なら、連続する2つのseparatorsへのマッチか、stringの最初か最後にマッチしたときの空文字列が結果に含まれる。omit-nullstなら、これらの空文字列は結果から除外される。

オプションの引数trimが非nilなら、その値は各部分文字列の最初と最後からトリム(trim: 除去)するテキストにマッチする正規表現を指定する。トリムによりその部分文字列が空になるようなら、それは空文字列として扱われる。

文字列を分割してcall-processstart-processに適するような、個々のコマンドライン引数のリストにする必要がある場合はsplit-string-and-unquoteを参照のこと。

以下は例:

(split-string "  two words ")
     ⇒ ("two" "words")

有用性はほとんどないであろう("" "two" "words" "")という結果とはならない。このような結果が必要ならseparatorsに明示的な値を使用すること

(split-string "  two words "
              split-string-default-separators)
     ⇒ ("" "two" "words" "")
(split-string "Soup is good food" "o")
     ⇒ ("S" "up is g" "" "d f" "" "d")
(split-string "Soup is good food" "o" t)
     ⇒ ("S" "up is g" "d f" "d")
(split-string "Soup is good food" "o+")
     ⇒ ("S" "up is g" "d f" "d")

空のマッチはカウントされます。例外は、空でないマッチを使用することにより、すでに文字列の最後に到達しているとき、またはstringが空の時で、この場合split-stringは最後の空マッチを探しません。

(split-string "aooob" "o*")
     ⇒ ("" "a" "" "b" "")
(split-string "ooaboo" "o*")
     ⇒ ("" "" "a" "b" "")
(split-string "" "")
     ⇒ ("")

しかしseparatorsが空文字列にマッチできるとき、通常はomit-nullstにすれば、前の3つの例の不明瞭さはほとんど発生しない:

(split-string "Soup is good food" "o*" t)
     ⇒ ("S" "u" "p" " " "i" "s" " " "g" "d" " " "f" "d")
(split-string "Nice doggy!" "" t)
     ⇒ ("N" "i" "c" "e" " " "d" "o" "g" "g" "y" "!")
(split-string "" "" t)
     ⇒ nil

空でないマッチより空のマッチを優先するような、一部の“非貪欲(non-greedy)”な値をseparatorsに指定することにより、幾分奇妙(ではあるが予見可能)な振る舞いが発生することがある。繰り返しになるが、そのような値は実際には稀である:

(split-string "ooo" "o*" t)
     ⇒ nil
(split-string "ooo" "\\|o+" t)
     ⇒ ("o" "o" "o")
Variable: split-string-default-separators

split-stringseparatorsにたいするデフォルト値。通常の値は"[ \f\t\n\r\v]+"


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

4.4 文字列の変更

このセクションで説明する処理を介して変更可能な文字列のコンテンツを変更できます。可変性を参照してください。

既存の文字列の内容を変更するもっとも基本的な方法は、aset (配列を操作する関数を参照)を使用する方法です。(aset string idx char)は、stringのインデックスidxに、charを格納します。それぞれの文字は1文字以上を占有しますが、すでにインデックスの場所にある文字のバイト数がcharが要するバイト数と異なる場合、asetはエラーをシグナルします。

より強力な関数はstore-substringです:

Function: store-substring string idx obj

この関数はインデックスidxで開始される位置にobjを格納することにより、文字列stringの内容の一部を変更する。objは文字、または(stringより小さい)文字列です。

既存の文字列の長さを変更するのは不可能なので、stringの実際の長さにobjが収まらない、またはstringのその位置に現在ある文字のバイト数が新しい文字に必要なバイト数と異なる場合はエラーになる。

パスワードを含む文字列をクリアーするときにはclear-stringを使用します:

Function: clear-string string

これはstringをユニバイト文字列にして、内容を0にクリアーする。これによりstringの長さも変更されるだろう。


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

4.5 文字および文字列の比較

Function: char-equal character1 character2

この関数は引数が同じ文字を表すならt、それ以外はnilをリターンする。case-fold-searchが非nilなら、この関数はcaseの違いを無視する。

(char-equal ?x ?x)
     ⇒ t
(let ((case-fold-search nil))
  (char-equal ?x ?X))
     ⇒ nil
Function: string= string1 string2

この関数は、2つの文字列の文字が正確にマッチすればtをリターンする。引数にはシンボルも指定でき、この場合はそのシンボル名が使用される。case-fold-searchとは無関係にcaseは常に意味をもつ。

この関数は、equalで2つの文字列を比較するのと等価である(同等性のための述語を参照)。特に、2つの文字列のテキストプロパティーは無視されます。テキストプロパティーだけが異なる文字列を区別する必要があるならequal-including-propertiesを使用すること。しかしequalとは異なり、いずれかの引数が文字列でもシンボルでもなければ、string=はエラーをシグナルする。

(string= "abc" "abc")
     ⇒ t
(string= "abc" "ABC")
     ⇒ nil
(string= "ab" "ABC")
     ⇒ nil

技術的な理由によりユニバイト文字列とマルチバイト文字列がequalになるのは、それらが同じ文字コードのシーケンスを含み、それらすべてのコードが0から127(ASCII)、または160から255(eight-bit-graphic)のときだけである。しかしユニバイト文字列をマルチバイト文字列に変更する際、コードが160から255の範囲にあるすべての文字はより高いコードに変換され、ASCII文字は変換されないまま残る。したがってユニバイト文字列とそれを変換したマルチバイト文字列は、その文字列のすべてがASCIIのときだけequalとなる。もしマルチバイト文字列中で文字コード160から255の文字があったとしても、それは完全に正しいとは言えない。結果として、すべてがASCIIではないユニバイト文字列とマルチバイト文字列がequalという状況は、もしかしたらEmacs Lispプロプラマーが直面するかもしれない、とても稀で記述的に不可解な状況だといえよう。テキストの表現方法を参照されたい。

Function: string-equal string1 string2

string-equalstring=の別名である。

Function: string-collate-equalp string1 string2 &optional locale ignore-case

この関数は照合ルール(collation rules)にもとづいてstring1string2が等しければtをリターンする。照合ルールはstring1string2に含まれる文字の辞書順だけではなく、それらの文字間の関係に関する他のルールにより判断される。これは通常は、Emacs実行中のlocale環境により決定される。

たとえば異なるコーディングポイントでも、Unicodeのグレイブアクセント文字のように同じ意味なら等しいとみなされる。

(string-collate-equalp (string ?\uFF40) (string ?\u1FEF))
     ⇒ t

オプション引数locale(文字列)は、照合用のカレントlocale識別子(current locale identifier)をオーバーライドする。値はシステムに依存する。たとえばPOSIXシステムでは"en_US.UTF-8"、MS-Windowsシステムでは"enu_USA.1252"localeが適用できるだろう。

ignore-caseが非nilなら、それらは比較前に小文字に変換される。

MS-WindowsシステムでUnicode互換の照合をエミュレートする場合、MS-Windowsではlocaleのコードセット部分を"UTF-8"にできないので、w32-collate-ignore-punctuationに非nil値をバインドすること。

あるlocale環境をシステムがサポートしなれければ、この関数はstring-equalと同様に振る舞う。

一般的にファイルシステムは照合ルールが実装するような文字列の言語学的な等価性を尊重しないので、この関数をファイル名の等価性の比較に使用しないこと

Function: string< string1 string2

この関数は2つの文字列を1文字ずつ比較する。この関数は同時に2つの文字列をスキャンして、対応する文字同士がマッチしない最初のペアを探す。2つの文字列内で小さいほうの文字がstring1の文字ならstring1が小さいことになり、この関数はtをリターンする。小さいほうの文字がstring2の文字ならstring1が大きいことになり、この関数はnilをリターンする。2つの文字列が完全にマッチしたら値はnilになる。

文字のペアーは文字コードで比較されル。ASCII文字セットでは英小文字は英大文字より高い数値をもつことに留意されたい。数字と区切り文字の多くは英大文字より低い数値をもつ。ASCII文字は任意の非ASCII文字より小さくなる。ユニバイトの非ASCII文字は、任意のマルチバイト非ASCII文字より常に小さくなります(テキストの表現方法を参照)。

(string< "abc" "abd")
     ⇒ t
(string< "abd" "abc")
     ⇒ nil
(string< "123" "abc")
     ⇒ t

文字列の長さが異なり、string1の長さまでマッチする場合、結果はtになる。string2の長さまでマッチする場合、結果はnilになる。文字を含まない文字列は、他の任意の文字列より小さくなる。

(string< "" "abc")
     ⇒ t
(string< "ab" "abc")
     ⇒ t
(string< "abc" "")
     ⇒ nil
(string< "abc" "ab")
     ⇒ nil
(string< "" "")
     ⇒ nil

引数としてシンボルを指定することもでき、この場合はシンボルのプリント名が比較される。

Function: string-lessp string1 string2

string-lesspstring<の別名である。

Function: string-greaterp string1 string2

この関数は逆順でstring1string2を比較した結果をリタンーする。つまりこれは(string-lessp string2 string1)を呼び出すのと等価である。

Function: string-collate-lessp string1 string2 &optional locale ignore-case

この関数は照合順でstring1string2より小さければtをリターンする。照合順はstring1string2に含まれる文字の辞書順だけではなく、それらの文字間の関係に関するルールによっても判断される。これは通常はEmacs実行中のlocale環境により決定される。

たとえばソートでは区切り文字と空白文字は無視されるだろう(シーケンスを参照)。

(sort (list "11" "12" "1 1" "1 2" "1.1" "1.2") 'string-collate-lessp)
     ⇒ ("11" "1 1" "1.1" "12" "1 2" "1.2")

Cygwinではlocaleと無関係に区切り文字と空白文字が無視されることが決してないように、この振る舞いはシステム依存である。

オプション引数locale(文字列)は、照合用のカレントlocale識別子(current locale identifier)をオーバーライドする。値はシステムに依存する。たとえばPOSIXシステムでは"en_US.UTF-8"、MS-Windowsシステムでは"enu_USA.1252"localeが適用できるだろう。localeの値を"POSIX""C"にすると、string-collate-lesspstring-lesspと同様に振る舞う。

(sort (list "11" "12" "1 1" "1 2" "1.1" "1.2")
      (lambda (s1 s2) (string-collate-lessp s1 s2 "POSIX")))
     ⇒ ("1 1" "1 2" "1.1" "1.2" "11" "12")

ignore-caseが非nilなら、それらは比較前に小文字に変換される。

MS-WindowsシステムでUnicode互換の照合をエミュレートする場合、MS-Windowsではlocaleのコードセット部分を"UTF-8"にできないので、w32-collate-ignore-punctuationに非nil値をバインドすること。

locale環境をサポートしないシステムでは、この関数はstring-lesspと同様に振る舞う。

Function: string-version-lessp string1 string2

この関数は文字列を辞書順で比較するが、数字のシーケンスを10進数で構成されているかのように扱い、その数値を比較する。つまりたとえ辞書順で‘12’が‘2’より“小”だとしても、この述語に応じて‘foo12.png’より‘foo2.png’が“小”になる。

Function: string-prefix-p string1 string2 &optional ignore-case

この関数はstring1string2のプレフィクス(たとえばstring2string1で始まる)なら、非nilをリターンする。オプションの引数ignore-caseが非nilばら、比較においてcaseの違いは無視される。

Function: string-suffix-p suffix string &optional ignore-case

この関数はsuffixstringのサフィックス(たとえばstringsuffixで終わる)なら、非nilをリターンする。オプションの引数ignore-caseが非nilなら、比較においてcaseの違いは無視される。

Function: compare-strings string1 start1 end1 string2 start2 end2 &optional ignore-case

この関数はstring1の指定部分をとstring2指定部分を比較する。string1の指定部分とは、インデックスstart1(その文字を含む)から、インデックスend1(その文字を含まない)まで。start1nilを指定すると文字列の最初という意味になり、end1nilを指定すると文字列の長さを意味する。同様にstring2の指定部分とはインデックスstart2からインデックスend2まで。

文字列は文字列内の文字の数値により比較される。たとえばstr1str2は、最初に異なる文字でstr1の文字の数値が小さければ小さいと判断される。ignore-caseが非nilなら比較を行なう前に大文字に変換される。比較用にユニバイト文字列はマルチバイト文字列に変換されるので(テキストの表現方法を参照)、ユニバイト文字列とそれを変換したマルチバイト文字列は常に等しくなる。

2つの文字列の指定部分がマッチした場合、値はtになる。それ以外なら値は整数で、何文字が一致してどちらの文字が小さいかを示す。この値の絶対値は、2つの文字列の先頭から一致した文字数に1加えた値になる。string1(または指定部分)のほうが小さければ符号は負になる。

Function: string-distance string1 string2 &optional bytecompare

この関数はソース文字列string1とターゲット文字列string2の間のレーベンシュタイン距離(Levenshtein distance)をリターンする。レーベンシュタイン距離はソース文字列をターゲット文字列に変換(削除、挿入、置換)するために必要な単一文字の個数。これは文字列間の編集距離(edit distance)として使用可能な定義の1つである。

計算距離にとって文字列の英字のcase(大文字小文字)は意味をもつが、テキストプロパティは無視される。オプション引数bytecompareが非nilなら、この関数は文字ではなくバイトで計算する。バイト単位での比較はEmacsの内部的な文字表現を使用するので、rawバイトを含むマルチバイト文字列では不正確な結果を生成するかもしれない(テキストの表現方法を参照)。rawで正確な結果が必要なら、エンコードして文字列をユニバイトにすること(明示的なエンコードとデコードを参照)。

Function: assoc-string key alist &optional case-fold

この関数はassocと同様に機能するが、keyは文字列かシンボルでなければならず、比較はcompare-stringsを使用して行なわれる。テストする前にシンボルは文字列に変換される。case-foldが非nilなら、keyalistの要素は比較前に大文字に変換される。assocとは異なり、この関数はコンスではない文字列またはシンボルのalist要素もマッチできる。特にalistは実際のalistではなく、文字列またはリストでも可。連想リストを参照のこと。

バッファー内のテキストを比較する方法として、テキストの比較の関数compare-buffer-substringsも参照してください。文字列にたいして正規表現のマッチを行なう関数string-matchも、ある種の文字列比較に使用することができます。正規表現の検索を参照してください。


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

4.6 文字および文字列の変換

このセクションでは文字、文字列、整数の間で変換を行なう関数を説明します。format (文字列のフォーマットを参照)とprin1-to-string (出力関数を参照)もLispオブジェクトを文字列に変換できます。read-from-string (入力関数を参照)は、Lispオブジェクトの文字列表現をオブジェクトに“変換”できます。関数string-to-multibytestring-to-unibyteは、テキスト表現を文字列に変換します(テキスト表現の変換を参照)。

テキスト文字と一般的なインプットイベントにたいするテキスト記述を生成する関数(single-key-descriptiontext-char-description)については、ドキュメントを参照してください。これらの関数は主にヘルプメッセージを作成するために使用されます。

Function: number-to-string number

この関数はnumberの10進プリント表現からなる文字列をリターンする。引数が負ならリターン値はマイナス記号から開始される。

(number-to-string 256)
     ⇒ "256"
(number-to-string -23)
     ⇒ "-23"
(number-to-string -23.5)
     ⇒ "-23.5"

int-to-stringはこの関数にたいする半ば廃れたエイリアスである。

文字列のフォーマットの関数formatも参照されたい。

Function: string-to-number string &optional base

この関数はstring内の文字の数値的な値をリターンする。baseが非nilなら値は2以上16以下でなければならず、整数はその基数に変換される。basenilなら基数に10が使用される。浮動少数点数の変換は基数が10のときだけ機能する。わたしたちは浮動小数点数にたいして他の基数を実装しない。なぜならこれには多くの作業を要し、その割にその機能が有用には思えないからだ。stringが整数のように見えるが、その値がLispの整数に収まらないほど大きな値なら、string-to-numberは浮動小数点数の結果をリターンする。

パースではstringの先頭にあるスペースとタブはスキップして、与えられた基数で数字として解釈できるところまでstringを読み取る(スペースとタブだけではなく先頭にある他の空白文字を無視するシステムもある)。stringを数字として解釈できなければこの関数は0をリターンする。

(string-to-number "256")
     ⇒ 256
(string-to-number "25 is a perfect square.")
     ⇒ 25
(string-to-number "X256")
     ⇒ 0
(string-to-number "-4.5")
     ⇒ -4.5
(string-to-number "1e5")
     ⇒ 100000.0

string-to-intはこの関数にたいする半ば廃れたエイリアスである。

Function: char-to-string character

この関数は1つの文字characterを含む新しい文字列をリターンする。関数stringのほうがより一般的であり、この関数は半ば廃れている。文字列の作成を参照のこと。

Function: string-to-char string

この関数はstringの最初の文字をリターンする。これはほとんど(aref string 0)と同じで、例外は文字列が空のときに0をリターンすること(文字列の最初の文字がASCIIコード0のヌル文字のときも0をリターンする)。この関数は残すのに充分なほど有用と思えないければ、将来削除されるかもしれない。

以下は文字列へ/からの変換に使用できるその他の関数です:

concat

この関数はベクターまたはリストから文字列に変換する。文字列の作成を参照のこと。

vconcat

この関数は文字列をベクターに変換する。ベクターのための関数を参照のこと。

append

この関数は文字列をリストに変換する。コンスセルおよびリストの構築を参照のこと。

byte-to-string

この関数は文字データのバイトをユニバイト文字列に変換する。テキスト表現の変換を参照のこと。


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

4.7 文字列のフォーマット

フォーマット(formatting)とは、定数文字列内のなまざまな場所を計算された値で置き換えることにより、文字列を構築することを意味します。この定数文字列は他の値がプリントされる方法、同様にどこに表示するかを制御します。これはフォーマット文字列(format string)と呼ばれます。

表示されるメッセージを計算するためにフォーマットが便利なことがしばしばあります。実際に関数messageerrorは、ここで説明する機能と同じフォーマットを提供します。これらの関数とformat-messageの違いはフォーマットされた結果を使用する方法だけです。

Function: format string &rest objects

この関数はstringのすべてのフォーマット仕様を、対応するobjectsを復号化したものと置換したものと等しい文字列をリターンする。引数objectsはフォーマットされる計算値。

(もしあれば)string内のフォーマット仕様以外の文字はテキストプロパティーを含めて出力に直接コピーされる。フォーマット仕様のすべてのテキストプロパティは引数objectsを表現する生成された文字列にコピーされる。

出力される文字列は新規に割り当てられる必要はない。たとえばxが文字列"foo"なら(eq x (format x))(eq x (format "%s" x))はいずれもtとなるだろう。

Function: format-message string &rest objects

この関数はformatと同様に機能するが、string内のすべてのグレイブアクセント(`)とアポストロフィー(')をtext-quoting-styleの各値に応じて変換する点が異なる。

フォーマット内のグレイブアクセントとアポストロフィーはマッチするcurved quotesに変換される("Missing `%s'""Missing ‘foo’"という結果になる)この変換の影響と回避についてはテキストのクォートスタイルを参照のこと。

フォーマット仕様(format specification)は‘%’で始まる文字シーケンスです。したがってstring内に‘%d’がるとformatはそれを、フォーマットされる値の1つ(引数objectsのうちの1つ)にたいするプリント表現で置き換えます。たとえば:

(format "The value of fill-column is %d." fill-column)
     ⇒ "The value of fill-column is 72."

formatは文字‘%’をフォーマット仕様と解釈するので、決して最初の引数に不定な文字列(arbitrary string)を渡すべきではありません。これは特に何らかのLispコードga生成siた文字列の場合に当てはまります。その文字列が決して文字‘%’を含まないと確信できないならば、以下で説明するように最初の引数に"%s"を渡して、不定な文字列を2番目の引数として渡します:

  (format "%s" arbitrary-string)

ある種のフォーマット仕様は特定の型の値を要求します。その要求に適合しない値を与えた場合にはエラーがシグナルされます。

以下は有効なフォーマット仕様のテーブルです:

%s

フォーマット仕様を、クォートなしのオブジェクトのプリント表現で置き換える(つまりprin1ではなくprincを使用して置き換える。出力関数を参照されたい)。したがって文字列は‘"’文字なしの文字列内容だけが表示され、シンボルは‘\’文字なしで表される。

オブジェクトが文字列なら文字列のプロパティーは出力にコピーされる。‘%s’のテキストプロパティー自身もコピーされるが、オブジェクトのテキストプロパティーが優先される。

%S

フォーマット仕様を、クォートありのオブジェクトのプリント表現で置き換える(つまりprin1を使用して変換する。出力関数を参照されたい)。したがって文字列は‘"’文字で囲まれ、必要となる特別文字の前に‘\’文字が表示される。

%o

フォーマット仕様を整数の8進表現に置き換える。負の整数はプラットフォーム依存の方法でフォーマットされる。オブジェクトは浮動小数点数(少数部分を切り捨てて整数にフォーマット)でもよい。

%d

フォーマット仕様を10進表現の符号すき整数で置き換える。オブジェクトは浮動小数点数(少数部分を切り捨てて整数にフォーマット)でもよい。

%x
%X

フォーマット仕様を16進表現の整数で置き換える。負の整数はプラットフォーム依存の方法でフォーマットされる。‘%x’なら小文字、‘%X’なら大文字が使用される。オブジェクトは少数部分を切り捨てて整数にフォーマットされた浮動小数点数でもよい。

%c

フォーマット仕様を与えられた値の文字で置き換える。

%e

フォーマット仕様を浮動小数点数の指数表現で置き換える。

%f

フォーマット仕様を浮動小数点数にたいする10進少数表記で置き換える。

%g

指数表記か小数点表記のいずれかを使用してフォーマット仕様を浮動小数点数にたいする表記に置き換える。指数が-4未満または精度(デフォルトは6)以上なら指数表記を使用する。デフォルトでは結果の少数部の末尾の0は削除されて、小数点が現れるのは後に数字が続く場合のみ。

%%

フォーマット仕様を1つの‘%’で置き換える。このフォーマット仕様は唯一のフォームが素の‘%%’であり値を使用しないという点で特殊。たとえば(format "%% %d" 30)"% 30"をリターンする。

他のフォーマット文字は‘Invalid format operation’エラーとなります。

以下は典型的なtext-quoting-styleのセッティングを想定した場合の例です:

(format "The octal value of %d is %o,
         and the hex value is %x." 18 18 18)
     ⇒ "The octal value of 18 is 22,
         and the hex value is 12."

(format-message
 "The name of this buffer is ‘%s’." (buffer-name))
     ⇒ "The name of this buffer is ‘strings-ja.texi’."

(format-message
 "The buffer object prints as `%s'." (current-buffer))
     ⇒ "The buffer object prints as ‘strings-ja.texi’."

フォーマット仕様はデフォルトではobjectsから連続して値を引き当てます。つまりstring内の1番目のフォーマット仕様は1番目の値、2番目のフォーマット仕様は2番目の値、...を使用します。余分なフォーマット仕様(対応する値がない場合)にはエラーとなります。フォーマットされる値が余分にある場合には無視されます。

フォーマット仕様はフィールド番号(field number)をもつことができます。これは最初の‘%’の直後に10進数字、その後にドル記号‘$’が続きます。これにより次の引数ではなく与えられた番号の引数をフォーマット仕様に変換させることができます。フィールド番号は1から始まります。フォーマットのフォーマット仕様が番号を含むことも含まないことも可能ですが、両方を含むことはできません。ただし例外は‘%%’であり、これは番号付きのフォーマット仕様と混交できます。

(format "%2$s, %3$s, %%, %1$s" "x" "y" "z")
     ⇒ "y, z, %, x"

%’とすべてのフィールド番号の後にフラグ文字(flag characters)を配置できます。

フラグ‘+’は非負の数の前にプラス符号を挿入するので、数には常に符号がつきます。フラグとしてスペースを指定すると、非負の数の前に1つのスペースが挿入されます(それ以外は非負の数は最初の数字から開始される)。これらのフラグは非負の数と負数にたいして確実に同じ列数を使用させるために有用です。これらは‘%d’、‘%e’、‘%f’、‘%g’以外では無視され、両方が指定された場合は‘+’が優先されます。

フラグ‘#’は代替形式(alternate form)を指定します。これは使用するフォーマットに依存します。‘%o’にたいしては結果を‘0’で開始させます。‘%x’と‘%X’にたいしては非0の結果のプレフィクスは‘0x’または‘0X’になります。‘%e’、‘%f’にたいしての‘#’フラグは、少数部が0のときにも小数点が含まれることを意味します。‘%g’にたいしては常に小数点が含まれるとともに、それ以外なら削除される小数点の後の末尾のすべての0も強制的に残されます。

フラグ‘0’はスペースの代わりに文字‘0’でパディングします。このフラグは‘%s’、‘%S’、‘%c’のような非数値のフォーマット仕様文字では無視されます。これらのフォーマット仕様文字で‘0’フラグを指定できますが、それでもスペースでパディングされます。

フラグ‘-’はフィールド幅指定子により挿入されるすべてのパディングに作用して、もしパディングが指定された場合には左側ではなく右側にパディングされます。‘-’と‘0’の両方が指定されると‘0’フラグは無視されます。

(format "%06d is padded on the left with zeros" 123)
     ⇒ "000123 is padded on the left with zeros"

(format "'%-6d' is padded on the right" 123)
     ⇒ "'123   ' is padded on the right"

(format "The word '%-7s' actually has %d letters in it."
        "foo" (length "foo"))
     ⇒ "The word 'foo    ' actually has 3 letters in it."

フォーマット仕様はフィールド幅(width)をもつことができます。これはすべてのフィールド番号とフラグの後にある10進の数字です。オブジェクトのプリント表現がこのフィールド幅より少ない文字w含む場合には、formatはパディングによりフィールド幅に拡張します。フォーマット仕様‘%%’ではフィールド幅の指定は無視されます。フィールド幅指定子により行なわれるパディングは、通常は左側に挿入されるスペースで構成されます:

(format "%5d is padded on the left with spaces" 123)
     ⇒ "  123 is padded on the left with spaces"

フィールド幅が小さすぎる場合でもformatはオブジェクトのプリント表現を切り詰めません。したがって情報を失う危険を犯すことなく、フィールドの最小幅を指定することができます。以下の2つの例では‘%7s’は最小幅に7を指定します。1番目の例では‘%7s’に挿入される文字列は3文字だけなので、4つのブランクスペースによりパディングされます。2番目の例では文字列"specification"は13文字ですが切り詰めはされません。

(format "The word '%7s' has %d letters in it."
        "foo" (length "foo"))
     ⇒ "The word '    foo' has 3 letters in it."
(format "The word '%7s' has %d letters in it."
        "specification" (length "specification"))
     ⇒ "The word 'specification' has 13 letters in it."

すべてのフォーマット仕様文字にはフィールド番号、フラグ、フィールド幅の後にオプションで精度(precision)を指定できます。精度は小数点‘.’と、その後に桁文字列(digit-string)を指定します。浮動少数点数のフォーマット仕様(‘%e’と‘%f’)では、精度は表示する小数点以下の桁数を指定します。0なら小数点も省略されます。%gの精度が0か未指定なら1として扱われます。‘%s’と‘%S’では精度として与えられた幅に文字列が切り詰められるので、‘%.3s’ではobjectの表現の最初の3文字だけが表示されます。その他の仕様文字では、printfファミリーのローカルライブラリーが生成する精度の効果が表れます。

%s’と‘%S’にたいしては、文字列を精度で指定された幅に切り詰めます。したがって‘%.3s’では、objectにたいするプリント表現の最初の3文字だけが表示されます。他のフォーマット仕様文字にたいしては、精度の効果はローカルライブラリーのprintf関数ファミリーが生成する効果となります。

フォーマット済みの値のコピーを取得するために後でreadを使用する予定なら、readが値を再構築する仕様を使用してください。この逆手順で数値をフォーマットするには‘%s’と‘%S’、整数だけなら‘%d’、非負の整数なら‘#x%x’と‘#o%o’も使用できます。その他のフォーマットでは問題があるかもしれません。たとえば‘%d’と‘%g’はNaNを誤って処理したり精度や型を失うかもしれず、‘#x%x’と‘#o%o’は負の整数を誤って処理するかもしれません。入力関数を参照してください。

このセクションでは仕様文字の固定セットを受け取る関数を説明します。次のセクションでは‘%a’や‘%z’のようなカスタム仕様文字を受け取ることができる関数format-specを説明します。


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

4.8 カスタムフォーマット文字列

ユーザーやLispプログラムが、カスタムフォーマットの制御文字列を介して特定のテキストが生成される方法を制御できるようにすると便利な場合があります。たとえばフォーマット文字列は人の姓や名、emailアドレスを表示する方法を制御できます。前のセクションで説明した関数formatを使用することにより、フォーマット文字列は"%s %s <%s>"のようになるかもしれません。しかしこのアプローチはどの仕様文字がどの情報に対応するかが不明瞭なのですぐに非実用的になります。

そのような場合には"%f %l <%e>"のようなフォーマット文字列のほうが便利かもしれません。このフォーマット文字列では仕様文字それぞれがより意味的な情報をもち、他の仕様文字に関連して簡単に再配置できるので、このようなフォーマット文字列はユーザーにより簡単にカスタマイズできます。

このセクションで説明する関数format-specformatと同様の機能を処理しますが、任意の仕様文字を使用するフォーマットコントロール文字列を処理する点が異なります。

Function: format-spec template spec-alist &optional only-present

この関数はspec-alistで指定された変換にしたがってフォーマット文字列templateから生成された文字列をリターンする。spec-alist(letter . replacement)という形式のalist(連想リストを参照)。template内の仕様%letterはそれぞれ結果文字列のフォーマット時に置換される。

(もしあれば)template内のフォーマット仕様以外の文字はテキストプロパティーを含めて出力に直接コピーされる。フォーマット仕様のすべてのテキストプロパティは置換先にコピーされる。

変換の指定にalistを使用することによって有用な特性がいくつか生成される:

オプション引数only-presentは、spec-alistで見つからないtemplate内の仕様文字の処理方法を示す。nilか省略なら、関数はエラーをシグナルする。それ以外ならこれらのフォーマット仕様およびtemplate内のすべての‘%%’は、(もしあれば)テキストプロパティも含めてそのまま出力される。

format-specが受け取るフォーマット仕様の構文はformatが受け取るフォーマット仕様と似ていますが同一ではありません。いずれの場合でもフォーマット仕様は‘%’で始まり‘s’のようなアルファベット文字で終わる文字シーケンスです。

仕様文字の固定セットに特定の意味を割り当てるformatとは異なり、format-specは任意の仕様文字を受け取ってそれらをすべて等しく扱います。たとえば:

(setq my-site-info
      (list (cons ?s system-name)
            (cons ?t (symbol-name system-type))
            (cons ?c system-configuration)
            (cons ?v emacs-version)
            (cons ?e invocation-name)
            (cons ?p (number-to-string (emacs-pid)))
            (cons ?a user-mail-address)
            (cons ?n user-full-name)))

(format-spec "%e %v (%c)" my-site-info)
     ⇒ "emacs 27.1 (x86_64-pc-linux-gnu)"

(format-spec "%n <%a>" my-site-info)
     ⇒ "Emacs Developers <emacs-devel@gnu.org>"

フォーマット仕様には置換の様相を変更するために、‘%’の直後に任意個数のフラグ文字を含めることができます。

0

このフラグは指定された幅のパディングをスペースのかわりに‘0’で構成する。

-

このフラグは指定された幅のパディングを左側ではなく右側に挿入する。

<

このフラグはもし幅が指定されたら置換の左側を切り捨てる。

>

このフラグはもし幅が指定されたら置換の右側を切り捨てる。

^

このフラグは置換されるテキストを大文字に変換する(Lispでの大文字小文字変換を参照)。

_

このフラグは置換されるテキストを小文字に変換する(Lispでの大文字小文字変換を参照)。

矛盾したフラグ(たとえば大文字と小文字)を使用した場合の結果は未定義です。

formatの場合と同様に、任意のフラグの後の10進数値として幅指定子をフォーマット仕様に含めることができます。指定した幅より置換の文字が少なければ左側がパディングされます。

(format-spec "%8a is padded on the left with spaces"
             '((?a . "alpha")))
     ⇒ "   alpha is padded on the left with spaces"

以下は前述の機能をいくつか組み合わせたより複雑な例です:

(setq my-battery-info
      (list (cons ?p "73")      ; パーセント表示
            (cons ?L "Battery") ; 状態
            (cons ?t "2:23")    ; 残り時間
            (cons ?c "24330")   ; 容量
            (cons ?r "10.6")))  ; 放電率

(format-spec "%>^-3L : %3p%% (%05t left)" my-battery-info)
     ⇒ "BAT :  73% (02:23 left)"

(format-spec "%>^-3L : %3p%% (%05t left)"
             (cons (cons ?L "AC")
                   my-battery-info))
     ⇒ "AC  :  73% (02:23 left)"

このセクションの例で示したように、format-specはさまざまな情報の断片を選択的にフォーマットするために頻繁に使用されます。これはプログラムが可能にする情報のサブセットだけをユーザーが通常の構文で望む順序で選択できるように、ユーザーにカスタマイズ可能なフォーマット文字列を提供するプログラムにとって有用です。


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

4.9 Lispでの大文字小文字変換

case変換関数(character case functions)は、1つの文字または文字列中の大文字小文字を変換します。関数は通常、アルファベット文字(英字‘A’から‘Z’と‘a’から‘z’、同様に非ASCIIの英字)だけを変換し、それ以外の文字は変換しません。caseテーブル(case table。caseテーブルを参照されたい)で指定することにより、caseの変換に異なるマッピングを指定できます。

これらの関数は引数として渡された文字列は変更しません。

以下の例では文字‘X’と‘x’を使用します。これらのASCIIコードは88と120です。

Function: downcase string-or-char

この関数はstring-or-char(文字か文字列)を小文字に変換する。

string-or-charが文字列なら、この関数は引数の大文字を小文字に変換した新しい文字列をリターンする。string-or-charが文字なら、この関数は対応する小文字(整数)をリターンする。元の文字が小文字か非英字ならリターン値は元の文字と同じ。

(downcase "The cat in the hat")
     ⇒ "the cat in the hat"

(downcase ?X)
     ⇒ 120
Function: upcase string-or-char

この関数はstring-or-char(文字か文字列)を大文字に変換する。

string-or-charが文字列なら、この関数は引数の小文字を大文字に変換した新しい文字列をリターンする。string-or-charが文字なら、この関数は対応する大文字(整数)をリターンする。元の文字が大文字か非英字ならリターン値は元の文字と同じ。

(upcase "The cat in the hat")
     ⇒ "THE CAT IN THE HAT"

(upcase ?x)
     ⇒ 88
Function: capitalize string-or-char

この関数は文字列や文字をキャピタライズ(capitalize: 先頭が大文字で残りは小文字)する。この関数はstring-or-charが文字列ならstring-or-charの各単語をキャピタライズした新たなコピーをリターンする。これは各単語の最初の文字が大文字に変換され、残りは小文字に変換されることを意味する。

単語の定義はカレント構文テーブル(current syntax table)の単語構成構文クラス(word constituent syntax class)に割り当てられた、連続する文字の任意シーケンスである(構文クラスのテーブルを参照)。

string-or-charが文字ならこの関数はupcaseと同じことを行なう。

(capitalize "The cat in the hat")
     ⇒ "The Cat In The Hat"

(capitalize "THE 77TH-HATTED CAT")
     ⇒ "The 77th-Hatted Cat"

(capitalize ?x)
     ⇒ 88
Function: upcase-initials string-or-char

この関数はstring-or-charが文字列なら、string-or-charの中の単語の頭文字をキャピタライズして、頭文字以外の文字は変更しない。この関数はstring-or-charの各単語の頭文字が大文字に変換された新しいコピーをリターンする。

単語の定義はカレント構文テーブル(current syntax table)の単語構成構文クラス(word constituent syntax class)に割り当てられた、連続する文字の任意シーケンスである(構文クラスのテーブルを参照)。

upcase-initialsの引数が文字なら、upcase-initialsの結果はupcaseと同じ。

(upcase-initials "The CAT in the hAt")
     ⇒ "The CAT In The HAt"

case変換コードポイントを1対1でマップするものではなく、結果の文字列長は引数の文字列長と異なるかもしれません。さらに文字を渡すことによりリターンされる型にも文字が強制されるので、関数は正しい置換を行えずに1文字の文字列を処理する場合とは結果が異なるかもしれません。たとえば:

(upcase "fi")  ; 注意: 1文字の合字 "fi"
     ⇒ "FI"
(upcase ?fi)
     ⇒ 64257  ; つまり ?fi

これを避けるためにはcase関数のいずれかに文字を渡す前にstring関数を使用して文字列に変換しなければなりません。もちろん結果の長さについて仮定はできません。

このような特殊ケースのマッピングはspecial-uppercasespecial-lowercasespecial-titlecaseから取得されます。文字のプロパティを参照してください。

文字列を比較する関数(caseの違いを無視するものや、オプションでcaseの違いを無視できるもの)については、文字および文字列の比較を参照されたい。


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

4.10 caseテーブル

特別なcaseテーブル(case table)をインストールすることにより、caseの変換をカスタマイズできます。caseテーブルは大文字と小文字の間のマッピングを指定します。caseテーブルはLispオブジェクトにたいするcase変換関数(前のセクションを参照)と、バッファー内のテキストに適用される関数の両方に影響します。それぞれのバッファーにはcaseテーブルがあります。新しいバッファーのcaseテーブルを初期化するために使用される、標準のcaseテーブル(standard case table)もあります。

caseテーブルは、サブタイプがcase-tableの文字テーブル(char-table。文字テーブルを参照)です。この文字テーブルはそれぞれの文字を対応する小文字にマップします。caseテーブルは、関連するテーブルを保持する3つの余分なスロットをもちます:

upcase

upcase(大文字)テーブルはそれぞれの文字を対応する大文字にマップする。

canonicalize

canonicalize(正準化)テーブルは、caseに関連する文字セットのすべてを、その文字セットの特別なメンバーにマップする。

equivalences

equivalence(同値)テーブルは、大の字小文字に関連した文字セットのそれぞれを、そのセットの次の文字にマップする。

単純な例では、小文字へのマッピングを指定することだけが必要です。3つの関連するテーブルは、このマッピングから自動的に計算されます。

大文字と小文字が1対1で対応しない言語もいくつかあります。これらの言語では、2つの異なる小文字が同じ大文字にマップされます。このような場合、大文字と小文字の両方にたいするマップを指定する必要があります。

追加のcanonicalizeテーブルは、それぞれの文字を正準化された等価文字にマップします。caseに関連する任意の2文字は、同じ正準等価文字(canonical equivalent character)をもちます。たとえば‘a’と‘A’はcase変換に関係があるので、これらの文字は同じ正準等価文字(両方の文字が‘a’、または両方の文字が‘A’)をもつべきです。

追加のequivalencesテーブルは、等価クラスの文字(同じ正準等価文字をもつ文字)それぞれを循環的にマップします(通常のASCIIでは、これは‘a’を‘A’に‘A’を‘a’にマップし、他の等価文字セットにたいしても同様にマップする)。

caseテーブルを構築する際は、canonicalizenilを指定できます。この場合、Emacsは大文字と小文字のマッピングでこのスロットを充填します。equivalencesにたいしてnilを指定することもできます。この場合、Emacsはcanonicalizeからこのスロットを充填します。実際に使用されるcaseテーブルでは、これらのコンポーネントは非nilです。canonicalizeを指定せずにequivalencesを指定しないでください。

以下はcaseテーブルに作用する関数です:

Function: case-table-p object

この述語は、objectが有効なcaseテーブルなら非nilをリターンする。

Function: set-standard-case-table table

この関数はtableを標準caseテーブルにして、これ以降に作成される任意のバッファーにたいしてこのテーブルが使用されるようにする。

Function: standard-case-table

これは標準caseテーブル(standard case table)をリターンする。

Function: current-case-table

この関数はカレントバッファーのcaseテーブルをリターンする。

Function: set-case-table table

これはカレントバッファーのcaseテーブルをtableにセットする。

Macro: with-case-table table body…

with-case-tableマクロはカレントcaseテーブルを保存してから、tableをカレントcaseテーブルにセットし、その後にbodyフォームを評価してから、最後にcaseテーブルをリストアします。リターン値は、bodyの最後のフォームの値です。throwかエラー(非ローカル脱出を参照)により異常終了した場合でも、caseテーブルはリストアされます。

ASCII文字のcase変換を変更する言語環境(language environment)がいくつかあります。たとえばトルコ語の言語環境では、ASCIIの大文字‘I’にたいする小文字は、トルコ語のドットがないi(‘ı’)です。これは(ASCIIベースのネットワークプロトコル実装のような)ASCIIの通常のcase変換を要求するコードに干渉する可能性があります。このような場合には、変数ascii-case-tableにたいしてwith-case-tableマクロを使用してください。これにより変更されていないASCII文字セットのcaseテーブルが保存されます。

Variable: ascii-case-table

ASCII文字セットにたいするcaseテーブル。すべての言語環境セッティングにおいて、これを変更するべきではない。

以下の3つの関数は、非ASCII文字セットを定義するパッケージにたいして便利なサブルーチンです。これらはcase-tableに指定されたcaseテーブルを変更します。これは標準構文テーブルも変更します。構文テーブルを参照してください。通常これらの関数は、標準caseテーブルを変更するために使用されます。

Function: set-case-syntax-pair uc lc case-table

この関数は対応する文字のペアー(一方は大文字でもう一方は小文字)を指定する。

Function: set-case-syntax-delims l r case-table

この関数は文字lrを、case不変区切り(case-invariant delimiter)のマッチングペアーとする。

Function: set-case-syntax char syntax case-table

この関数はcharを構文syntaxのcase不変(case-invariant)とする。

Command: describe-buffer-case-table

このコマンドはカレントバッファーのcaseテーブルの内容にたいする説明を表示する。


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

5 リスト

リスト(list)は0個以上の要素(任意のLispオブジェクト)のシーケンスを表します。リストとベクターの重要な違いは、2つ以上のリストが構造の一部を共有できることです。加えて、リスト全体をコピーすることなく要素の挿入と削除ができます。


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

5.1 リストとコンスセル

Lispでのリストは基本データ型ではありません。リストはコンスセル(cons cells)から構築されます(コンスセルとリスト型を参照)。コンスセルは順序つきペアを表現するデータオブジェクトです。つまりコンスセルは2つのスロットをもち、それぞれのスロットはLispオブジェクトを保持(holds)または参照(refers to)します。1つのスロットはCAR、もう1つはCDRです(これらの名前は歴史的なものである。コンスセルとリスト型を参照されたい)。CDRは“could-er(クダー)”と発音します。

わたしたちは、コンスセルのCARスロットに現在保持されているオブジェクトが何であれ、“このコンスセルのCARは、...”のような言い方をします。これはCDRの場合でも同様です。

リストとは互いに連なる(chained together)一連のコンスセルであり、各セルは次のセルを参照します。リストの各要素にたいして1つのコンスセルがあります。慣例によりコンスセルのCARはリストの要素を保持し、CDRはリストをチェーンするのに使用されます(CARCDRの間の非対称性は完全に慣例的なものである。コンスセルのレベルではCARスロットとCDRスロットは同じようなプロパティーをもつ)。したがって、リスト内の各コンスセルのCDRスロットは次のコンスセルを参照します。

これも慣例的なものですがリスト内の最後のコンスセルのCDRnilです。わたしたちはこのようなnilで終端された構造を正リスト(proper list)と呼びます3。Emacs Lispではシンボルnilはシンボルであり、かつ要素なしのリストでもあります。便宜上、シンボルnilはそのCDR(とCAR)にnilをもつと考えます。

したがって正リストのCDRは常に正リストです。空でない正リストのCDRは1番目の要素以外を含む正リストです。

リストの最後のコンスセルのCDRnil以外の何らかの値の場合、このリストのプリント表現はドットペア表記(dotted pair notation。ドットペア表記を参照のこと)を使用するので、わたしたちはこの構造をドットリスト(dotted list)と呼びます。他の可能性もあります。あるコンスセルのCDRが、そのリストのそれより前にある要素を指すかもしれません。わたしたちは、この構造を循環リスト(circular list)と呼びます。

ある目的においてはそのリストが正リストか循環リストなのか、あるいはドットリストなのかが問題にならない場合もあります。そのプログラムがリストを充分に辿って最後のコンスセルのCDRを確認しようとしないなら、これは問題になりません。しかしリストを処理する関数のいくつかは正リストを要求し、ドットリストの場合はエラーをシグナルします。リストの最後を探そうと試みる関数のほとんどは循環リストを与えると無限ループに突入します。

ほとんどのコンスセルはリストの一部として使用されるので、わたしたちはコンスセルで構成される任意の構造をリスト構造(list structure)と呼びます。


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

5.2 リストのための述語

以下の述語はあるLispオブジェクトがアトムか、コンスセルか、リストなのか、またはオブジェクトがnilかどうかテストします(これらの述語の多くは他の述語で定義することもできるが、多用されるので個別に定義する価値がある)。

Function: consp object

この関数はobjectがコンスセルならt、それ以外はnilをリターンする。たとえnilリストであっても、コンスセルではない。

Function: atom object

この関数はobjectがアトムならt、それ以外はnilをリターンする。シンボルnilはアトムであり、かつリストでもある。そのようなLispオブジェクトはnilだけである。

(atom object) ≡ (not (consp object))
Function: listp object

この関数はobjectがコンスセルかnilならt、それ以外はnilをリターンする。

(listp '(1))
     ⇒ t
(listp '())
     ⇒ t
Function: nlistp object

この関数はlistpの反対である。objectがリストでなければt、それ以外はnilをリターンする。

(listp object) ≡ (not (nlistp object))
Function: null object

この関数はobjectnilならt、それ以外はnilをリターンする。この関数はnotと等価だが、明解にするためにobjectをリストだと考えるときはnull、真偽値だと考えるときはnotを使用すること(組み合わせ条件の構築notを参照)。

(null '(1))
     ⇒ nil
(null '())
     ⇒ t
Function: proper-list-p object

この関数はobjectが適正なリストならobjectの長さ、それ以外はnilをリターンする(リストとコンスセルを参照)。適正なリストとはlistpを満足することに加えて、循環リストやドットリストでもない。

(proper-list-p '(a b c))
    ⇒ 3
(proper-list-p '(a b . c))
    ⇒ nil

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

5.3 リスト要素へのアクセス

Function: car cons-cell

この関数はコンスセルcons-cellの1番目のスロットが参照する値をリターンする。言い換えるとこの関数はcons-cellCARをリターンする。

特別なケースとしてcons-cellnilの場合、この関数はnilをリターンする。したがってリストはすべて引数として有効である。引数がコンスセルでもnilでもなければエラーがシグナルされる。

(car '(a b c))
     ⇒ a
(car '())
     ⇒ nil
Function: cdr cons-cell

この関数はコンスセルcons-cellの2番目のスロットにより参照される値をリターンする。言い換えるとこの関数はcons-cellCDRをリターンする。

特別なケースとしてcons-cellnilの場合、この関数はnilをリターンする。したがってリストはすべて引数として有効である。引数がコンスセルでもnilでもければエラーがシグナルされる。

(cdr '(a b c))
     ⇒ (b c)
(cdr '())
     ⇒ nil
Function: car-safe object

この関数により他のデータ型によるエラーを起こさずに、コンスセルのCARを取得できり。この関数はobjectがコンスセルならobjectCAR、それ以外はnilをリターンする。この関数は、objectがリストでなければエラーをシグナルするcarとは対象的である。

(car-safe object)
≡
(let ((x object))
  (if (consp x)
      (car x)
    nil))
Function: cdr-safe object

この関数により他のデータ型によるエラーを起こさずに、コンスセルのCDRを取得できる。この関数はobjectがコンスセルならobjectCDR、それ以外はnilをリターンする。この関数は、objectがリストでないときはエラーをシグナルするcdrとは対象的である。

(cdr-safe object)
≡
(let ((x object))
  (if (consp x)
      (cdr x)
    nil))
Macro: pop listname

このマクロはリストのCARを調べて、それをリストから取り去るのを一度に行なう便利な方法を提供する。この関数はlistnameに格納されたリストにたいして処理を行なう。この関数はリストから1番目の要素を削除して、CDRlistnameに保存し、その後で削除した要素をリターンする。

もっとも単純なケースは、リストに名前をつけるためのクォートされていないシンボルの場合である。この場合、このマクロは(prog1 (car listname) (setq listname (cdr listname)))と等価である。

x
     ⇒ (a b c)
(pop x)
     ⇒ a
x
     ⇒ (b c)

より一般的なのはlistnameが汎変数(generalized variable)の場合である。この場合、このマクロはsetfを使用してlistnameに保存する。ジェネリック変数を参照のこと。

リストに要素を追加するpushマクロについてはリスト変数の変更を参照のこと。

Function: nth n list

この関数はlistn番目の要素をリターンする。要素は0から数えられるのでlistCARは要素0になる。listの長さがn以下なら値はnil

(nth 2 '(1 2 3 4))
     ⇒ 3
(nth 10 '(1 2 3 4))
     ⇒ nil

(nth n x) ≡ (car (nthcdr n x))

これは関数eltも類似しているが、任意の種類のシーケンスに適用される。歴史的な理由によりこの関数は逆の順序で引数を受け取る。シーケンスを参照のこと。

Function: nthcdr n list

この関数はlistn番目のCDRをリターンする。言い換えると、この関数はlistの最初のn個のリンクをスキップしてから、それ以降をリターンする。

nが0ならnthcdrlist全体をリターンする。listの長さがn以下ならnthcdrnilをリターンする。

(nthcdr 1 '(1 2 3 4))
     ⇒ (2 3 4)
(nthcdr 10 '(1 2 3 4))
     ⇒ nil
(nthcdr 0 '(1 2 3 4))
     ⇒ (1 2 3 4)
Function: last list &optional n

この関数はlistの最後のリンクをリターンする。このリンクのcarはこのリストの最後の要素。listがnullならnilがリターンされる。nが非nilならn番目から最後までのリンクがリターンされる。nlistの長さより大きければlist全体がリターンされる。

Function: safe-length list

この関数はエラーや無限ループの危険なしで、listの長さをリターンする。この関数は一般的に、リスト内のコンスセルの個数をリターンする。しかし循環リストでは単に上限値が値となるため、非常に大きくなる場合があります。

listnil]とコンスセルのいずれでもなければsafe-lengthは0をリターンする。

循環リストを考慮しなくてもよい場合にリストの長さを計算するもっとも一般的な方法は、lengthを使う方法です。シーケンスを参照してください。

Function: caar cons-cell

これは(car (car cons-cell))と同じ。

Function: cadr cons-cell

これは(car (cdr cons-cell))(nth 1 cons-cell)と同じ。

Function: cdar cons-cell

これは(cdr (car cons-cell))と同じ。

Function: cddr cons-cell

これは(cdr (cdr cons-cell))(nthcdr 2 cons-cell)と同じ。

上記に加えてcxxxrcxxxxrのようなcarcdrで構成される24の関数が定義されています。ここでxadのいずれかです。cadrcaddrcadddrはそれぞれリストの2つ目、3つ目、4つ目の要素です。cl-libは同じものをcl-secondcl-thirdcl-fourthという名前で提供しています。List Functions in Common Lisp Extensionsを参照してください。

Function: butlast x &optional n

この関数はリストxから、最後の要素か最後のn個の要素を削除してリターンする。nが0より大きければこの関数はリストのコピーを作成するので、元のリストに影響はない。一般的に(append (butlast x n) (last x n))は、xと等しいリストをリターンする。

Function: nbutlast x &optional n

この関数はリストのコピーを作成するのではなく、cdrを適切な要素に変更することにより破壊的に機能するバージョンのbutlastである。


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

5.4 コンスセルおよびリストの構築

リストはLispの中核にあたる機能なので、リストを構築するために多くの関数があります。consはリストを構築する基本的な関数です。しかしEmacsのソースコードでは、consよりlistのほうが多く使用されているのは興味深いことです。

Function: cons object1 object2

この関数は新しいリスト構造を構築するための、もっとも基本的な関数である。この関数はobject1CARobject2CDRとする新しいコンスセルを作成して、それから新しいコンスセルをリターンする。引数object1object2には任意のLispオブジェクトを指定できるが、ほとんどの場合object2はリストである。

(cons 1 '(2))
     ⇒ (1 2)
(cons 1 '())
     ⇒ (1)
(cons 1 2)
     ⇒ (1 . 2)

リストの先頭に1つの要素を追加するために、consがよく使用される。これをリストに要素をコンスすると言います。4たとえば:

(setq list (cons newelt list))

この例で使用されているlistという名前の変数と、以下で説明するlistという名前の関数は競合しないことに注意されたい。すべてのシンボルが、変数ト関数の両方の役割を果たすことができる。

Function: list &rest objects

この関数はobjectsを要素とするリストを作成する。結果となるリストは常にnil終端される。objectsを指定しないと空リストがリターンされる。

(list 1 2 3 4 5)
     ⇒ (1 2 3 4 5)
(list 1 2 '(3 4 5) 'foo)
     ⇒ (1 2 (3 4 5) foo)
(list)
     ⇒ nil
Function: make-list length object

この関数は各要素がobjectであるような、length個の要素からなるリストを作成する。make-listmake-string(文字列の作成を参照)を比較してみよ。

(make-list 3 'pigs)
     ⇒ (pigs pigs pigs)
(make-list 0 'pigs)
     ⇒ nil
(setq l (make-list 3 '(a b)))
     ⇒ ((a b) (a b) (a b))
(eq (car l) (cadr l))
     ⇒ t
Function: append &rest sequences

この関数はsequencesのすべての要素を含むリストをreturnします。sequencesにはリスト、ベクター、ブールベクター、文字列も指定できるが、通常は最後にリストを指定すること。最後の引数を除くすべての引数はコピーされるので、変更される引数はない(コピーを行なわずにリストを結合する方法についてはリストを再配置する関数nconcを参照のこと)。

より一般的にはappendにたいする最後の引数は任意のLispオブジェクトを指定できる。最後の引数のコピーや変換は行わない。最後の引数は新しいリストの最後のコンスセルのCDRとなる。最後の引数もリストならば、このリストの要素は実質的には結果リストの要素になる。最後の要素がリストでなければ、最後のCDRが(正リストで要求される)nilではないので結果はドットリストになる(リストとコンスセルを参照)。

以下はappendを使用した例です:

(setq trees '(pine oak))
     ⇒ (pine oak)
(setq more-trees (append '(maple birch) trees))
     ⇒ (maple birch pine oak)

trees
     ⇒ (pine oak)
more-trees
     ⇒ (maple birch pine oak)
(eq trees (cdr (cdr more-trees)))
     ⇒ t

appendがどのように機能するか、ボックスダイアグラムで確認できます。変数treesはリスト(pine oak)にセットされ、それから変数more-treesにリスト(maple birch pine oak)がセットされます。しかし変数treesは継続して元のリストを参照します:

more-trees                trees
|                           |
|     --- ---      --- ---   -> --- ---      --- ---
 --> |   |   |--> |   |   |--> |   |   |--> |   |   |--> nil
      --- ---      --- ---      --- ---      --- ---
       |            |            |            |
       |            |            |            |
        --> maple    -->birch     --> pine     --> oak

空のシーケンスはappendによりリターンされる値に寄与しません。この結果、最後の引数にnilを指定すると、それより前の引数のコピーを強制することになります。

trees
     ⇒ (pine oak)
(setq wood (append trees nil))
     ⇒ (pine oak)
wood
     ⇒ (pine oak)
(eq wood trees)
     ⇒ nil

関数copy-sequenceが導入される以前は,これがリストをコピーする通常の方法でした。シーケンス、配列、ベクターを参照してください。

以下はappendの引数としてベクターと文字列を使用する例です:

(append [a b] "cd" nil)
     ⇒ (a b 99 100)

apply (関数の呼び出しを参照)の助けを借りることにより、リストのリストの中のすべてのリストをappendできます。

(apply 'append '((a b c) nil (x y z) nil))
     ⇒ (a b c x y z)

sequencesが与えられなければnilがリターンされます:

(append)
     ⇒ nil

以下は最後の引数がリストでない場合の例です:

(append '(x y) 'z)
     ⇒ (x y . z)
(append '(x y) [z])
     ⇒ (x y . [z])

2番目の例は最後の引数はリストではないシーケンスの場合で、このシーケンスの要素は、結果リストの要素にはなりません。かわりに最後の引数がリストでないときと同様、シーケンスが最後のCDRになります。

Function: copy-tree tree &optional vecp

この関数はツリーtreeのコピーをリターンする。treeがコンスセルなら同じCARCDRをもつ新しいコンスセルを作成してから、同じ方法によってCARCDRを再帰的にコピーする。

treeがコンスセル以外の場合、通常はcopy-treeは単にtreeをリターンする。しかしvecpが非nilなら、この関数はベクターでもコピーします(そしてベクターの要素を再帰的に処理する)。

Function: flatten-tree tree

この関数はtreeを“平坦化”したコピー( treeをルートとするコンスセルのツリーのすべての非nilな終端nodeとleave)をリターンする。リターンされたリストのleaveの順序はtreeでの順序と同じ。

(flatten-tree '(1 (2 . 3) nil (4 5 (6)) 7))
    ⇒(1 2 3 4 5 6 7)
Function: number-sequence from &optional to separation

この関数はfromからseparationづつインクリメントして、toの直前で終わる数字のリストをリターンする。separationには正か負の数を指定でき、デフォルトは1。tonil、または数値的にfromと等しければ、値は1要素のリスト(from)になる。separationが正でtofromより小さい、またはseparationが負でtofromより大きければ、これらの引数は空のシーケンスを指示することになるので、値はnilになる。

separationが0で、tonilでもなく、数値的にfromとも等しくまければ、これらの引数は無限シーケンスを指示することになるので、エラーがシグナルされる。

引数はすべて数字である。浮動少数点数の計算は正確ではないので、浮動少数点数の引数には注意する必要がある。たとえばマシンへの依存により、(number-sequence 0.4 0.8 0.2)が3要素のリストをリターンして、(number-sequence 0.4 0.6 0.2)が1要素のリスト(0.4)をリターンnすることがよく起こる。リストのn番目の要素は、厳密に(+ from (* n separation))という式により計算される。リストに確実にtoが含まれるようにするために、この式に適切な型のtoを渡すことができる。別の方法としてtoを少しだけ大きな値(separationが負なら少しだけ小さな値)に置き換えることもできる。

例をいくつか示す:

(number-sequence 4 9)
     ⇒ (4 5 6 7 8 9)
(number-sequence 9 4 -1)
     ⇒ (9 8 7 6 5 4)
(number-sequence 9 4 -2)
     ⇒ (9 7 5)
(number-sequence 8)
     ⇒ (8)
(number-sequence 8 5)
     ⇒ nil
(number-sequence 5 8 -1)
     ⇒ nil
(number-sequence 1.5 6 2)
     ⇒ (1.5 3.5 5.5)

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

5.5 リスト変数の変更

以下の関数と1つのマクロは、変数に格納されたリストを変更する便利な方法を提供します。

Macro: push element listname

このマクロはCARelementで、CDRlistnameのリストであるような新しいリストを作成して、そのリストをlistnameに保存する。listnameがリストに名前をつけるクォートされていないシンボルのときは単純で、この場合マクロは(setq listname (cons element listname))と等価になる。

(setq l '(a b))
     ⇒ (a b)
(push 'c l)
     ⇒ (c a b)
l
     ⇒ (c a b)

より一般的なのはlistnameが汎変数の場合である。この場合、このマクロは(setf listname (cons element listname))と等価になる。ジェネリック変数を参照のこと。

リストから1番目の要素を取り出すpopマクロについては、リスト要素へのアクセスを参照されたい。

以下の2つの関数は、変数の値であるリストを変更します。

Function: add-to-list symbol element &optional append compare-fn

この関数はelementsymbolの値のメンバーでなければ、symbolelementをコンスすることにより、変数symbolをセットする。この関数はリストが更新されているか否かに関わらず、結果のリストをリターンする。symbolの値は呼び出し前にすでにリストであることが望ましい。elementがリストの既存メンバーか比較するために、add-to-listcompare-fnを使用する。compare-fnnilならequalを使用する。

elementが追加される場合は、通常はsymbolの前に追加されるが、オプションの引数appendが非nilなら最後に追加される。

引数symbolは暗黙にクォートされない。setqとは異なりadd-to-listsetのような通常の関数である。クォートしたい場合には自分で引数をクォートすること。

symbolがレキシカル変数を参照する際にはこの関数を使用しないこと。

以下に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)と等価な式です:

(if (member value var)
    var
  (setq var (cons value var)))
Function: add-to-ordered-list symbol element &optional order

この関数は古い値のorder (リストであること)で指定された位置に、elementを挿入して変数symbolをセットする。elementがすでにこのリストのメンバなら、リスト内の要素の位置はorderにしたがって調整される。メンバーか否かはeqを使用してテストされる。この関数は更新されているかどうかに関わらず、結果のリストをリターンする。

orderは通常は数字(整数か浮動小数点数)で、リストの要素はその数字の昇順で並べられる。

orderは省略またはnilを指定できる。これによりリストにelementがすでに存在するなら、elementの数字順序は変更されない。それ以外ならelementは数字順序をもたない。リストの数字順序をもたない要素はリストの最後に配置され、特別な順序はつかない。

orderに他の値を指定すると、elementがすでに数字順序をもつときは数字順序が削除される。それ以外はならnilと同じ。

引数symbolは暗黙にクォートされない。add-to-ordered-listsetqなどとは異なり、setのような通常の関数である。必要なら引数を自分でクォートすること。

順序の情報はsymbollist-orderプロパティーにハッシュテーブルで保存される。symbolはレキシカル変数を参照できない。

以下にadd-to-ordered-listを使用する方法をシナリオで示します:

(setq foo '())
     ⇒ nil

(add-to-ordered-list 'foo 'a 1)     ;; aを追加
     ⇒ (a)

(add-to-ordered-list 'foo 'c 3)     ;; cを追加
     ⇒ (a c)

(add-to-ordered-list 'foo 'b 2)     ;; bを追加
     ⇒ (a b c)

(add-to-ordered-list 'foo 'b 4)     ;; bを移動
     ⇒ (a c b)

(add-to-ordered-list 'foo 'd)       ;; dを後に追加
     ⇒ (a c b d)

(add-to-ordered-list 'foo 'e)       ;; eを追加
     ⇒ (a c b e d)

foo                       ;; fooが変更された
     ⇒ (a c b e d)

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

5.6 既存のリスト構造の変更

プリミティブsetcarsetcdrでコンスセルのCARおよびCDRのコンテンツを変更できます。これらは既存のリスト構造を変更するので破壊的な操作です。破壊的操作はmutable(変更可能)なリスト、すなわちconslist、または類似の操作により構築される必要があります。クォートにより作成されたリストはプログラムの一部であり、破壊的な操作により変更するべきではありません。可変性を参照してください。

Common Lispに関する注意: Common Lispはリスト構造の変更にrplacarplacdを使用する。これらはsetcarsetcdrと同じ方法でリスト構造を変更するが、setcarsetcdrは新しいCARCDRをリターンするのにたいして、Common Lispの関数はコンスセルをリターンする。


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

5.6.1 setcarによるリスト要素の変更

コンスセルのCARの変更はsetcarで行ないます。リストにたいして使用するとsetcarはリストの1つの要素を別の要素に置き換えます。

Function: setcar cons object

この関数は以前のCARを置き換えて、consの新しいCARobjectを格納する。言い換えると、この関数はconsCARスロットをobjectを参照するように変更する。この関数は値objectをリターンする。たとえば:

(setq x (list 1 2))
     ⇒ (1 2)
(setcar x 4)
     ⇒ 4
x
     ⇒ (4 2)

コンスセルが複数のリストを共有する構造の一部なら、コンスに新しいCARを格納することにより、これら共有されたリストの各1つの要素を変更します。以下は例です:

;; 部分的に共有された2つのリストを作成
(setq x1 (list 'a 'b 'c))
     ⇒ (a b c)
(setq x2 (cons 'z (cdr x1)))
     ⇒ (z b c)

;; 共有されたリンクのCARを置き換え
(setcar (cdr x1) 'foo)
     ⇒ foo
x1                           ; 両方のリストが変更された
     ⇒ (a foo c)
x2
     ⇒ (z foo c)

;; 共有されていないリンクのCARを置き換え
(setcar x1 'baz)
     ⇒ baz
x1                           ; 1つのリストだけが変更された
     ⇒ (baz foo c)
x2
     ⇒ (z foo c)

なぜbを置き換えると両方が変更されるのかを説明するために、変数x1x2の2つのリストによる共有構造を視覚化してみましょう:

        --- ---        --- ---      --- ---
x1---> |   |   |----> |   |   |--> |   |   |--> nil
        --- ---        --- ---      --- ---
         |        -->   |            |
         |       |      |            |
          --> a  |       --> b        --> c
                 |
       --- ---   |
x2--> |   |   |--
       --- ---
        |
        |
         --> z

同じ関係を別のボックス図で示すと、以下のようになります:

x1:
 --------------       --------------       --------------
| car   | cdr  |     | car   | cdr  |     | car   | cdr  |
|   a   |   o------->|   b   |   o------->|   c   |  nil |
|       |      |  -->|       |      |     |       |      |
 --------------  |    --------------       --------------
                 |
x2:              |
 --------------  |
| car   | cdr  | |
|   z   |   o----
|       |      |
 --------------

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

5.6.2 リストのCDRの変更

CDRを変更するもっとも低レベルのプリミティブ関数はsetcdrです:

Function: setcdr cons object

この関数は前のCDRを置き換えて、consの新しいCDRobjectを格納する。言い換えると、この関数はconsCDRobjectを参照するように変更する。この関数は値objectをリターンする。

以下はリストのCDRを、他のリストに置き換える例です。1番目の要素以外のすべての要素は、別のシーケンスまたは要素のために取り除かれます。1番目の要素はリストのCARなので変更されず、CDRを通じて到達することもできないからです。

(setq x (list 1 2 3))
     ⇒ (1 2 3)
(setcdr x '(4))
     ⇒ (4)
x
     ⇒ (1 4)

リスト内のコンスセルのCDRを変更することにより、リストの途中から要素を削除できます。たとえば以下では、1番目のコンスセルのCDRを変更することにより、2番目の要素bをリスト(a b c)から削除します。

(setq x1 (list 'a 'b 'c))
     ⇒ (a b c)
(setcdr x1 (cdr (cdr x1)))
     ⇒ (c)
x1
     ⇒ (a c)

以下に結果をボックス表記で示します:

                   --------------------
                  |                    |
 --------------   |   --------------   |    --------------
| car   | cdr  |  |  | car   | cdr  |   -->| car   | cdr  |
|   a   |   o-----   |   b   |   o-------->|   c   |  nil |
|       |      |     |       |      |      |       |      |
 --------------       --------------        --------------

以前は要素bを保持していた2番目のコンスセルは依然として存在し、そのCARbのままですが、すでにこのリストの一部を形成していません。

CDRを変更して新しい要素を挿入するのも同じくらい簡単です:

(setq x1 (list 'a 'b 'c))
     ⇒ (a b c)
(setcdr x1 (cons 'd (cdr x1)))
     ⇒ (d b c)
x1
     ⇒ (a d b c)

以下に結果をボックス表記で示します:

 --------------        -------------       -------------
| car  | cdr   |      | car  | cdr  |     | car  | cdr  |
|   a  |   o   |   -->|   b  |   o------->|   c  |  nil |
|      |   |   |  |   |      |      |     |      |      |
 --------- | --   |    -------------       -------------
           |      |
     -----         --------
    |                      |
    |    ---------------   |
    |   | car   | cdr   |  |
     -->|   d   |   o------
        |       |       |
         ---------------

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

5.6.3 リストを再配置する関数

以下ではリストの構成要素であるコンスセルのCDRを変更することにより、リストを破壊的に再配置する関数をいくつか示します。これらの関数が破壊的だという理由は、これらの関数が引数として渡された元のリストを処理してリターン値となる新しいリストを形成するために、リストのコンスセルを再リンクするからです。

コンスセルを変更する他の関数については、集合としてのリストの使用delqを参照してください。

Function: nconc &rest lists

この関数はlistsの要素すべてを含むリストをリターンする。append (コンスセルおよびリストの構築を参照)とは異なり、listsコピーされない。かわりにlistsの各リストの最後のCDRが次のリストを参照するように変更される。listsの最後のリストは変更されない。たとえば:

(setq x (list 1 2 3))
     ⇒ (1 2 3)
(nconc x '(4 5))
     ⇒ (1 2 3 4 5)
x
     ⇒ (1 2 3 4 5)

nconcの最後の引数は変更されないので、上記の例のように'(4 5)のような定数リストを使用するのが合理的である。また同じ理由により最後の引数がリストである必要はない。

(setq x (list 1 2 3))
     ⇒ (1 2 3)
(nconc x 'z)
     ⇒ (1 2 3 . z)
x
     ⇒ (1 2 3 . z)

しかし他の(最後を除くすべての)引数はmutableリストでなければなければならない。

一般的な落とし穴としては、nconcにたいしてリスト定数を最後以外の引数として使用した場合である。これを行なった場合の結果としての挙動は未定義である。実行するごとにプログラムはリスト定数を変更する可能性がある! (必ず発生する保証はないが)以下のようなことが起こり得る:

(defun add-foo (x)            ; この関数ではfoo
  (nconc '(foo) x))           ;   を引数の前に追加したい

(symbol-function 'add-foo)
     ⇒ (lambda (x) (nconc '(foo) x))

(setq xx (add-foo '(1 2)))    ; 動いているように見える
     ⇒ (foo 1 2)
(setq xy (add-foo '(3 4)))    ; 何が起きているのか?
     ⇒ (foo 1 2 3 4)
(eq xx xy)
     ⇒ t

(symbol-function 'add-foo)
     ⇒ (lambda (x) (nconc '(foo 1 2 3 4) x))

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

5.7 集合としてのリストの使用

リストは順序なしの数学的集合 — リスト内に要素があれば集合の要素の値としてリスト内の順序は無視される — を表すことができます。2つの集合を結合(union)するには、(重複する要素を気にしなければ)appendを使用します。equalである重複を取り除くにはdelete-dupsを使用します。集合にたいする他の有用な関数にはmemqdelqや、それらのequalバージョンであるmemberdeleteが含まれます。

Common Lispに関する注意: 集合を処理するためにCommon Lispには関数union (要素の重複がない)とintersectionがある。Emacs Lispではcl-libがこれらの変種を提供する。Lists as Sets in Common Lisp Extensionsを参照のこと。

Function: memq object list

この関数はobjectlistのメンバーかどうかをテストする。メンバーならmemqは、objectで最初に見つかった要素から開始されるリストをリターンする。メンバーでなければnilをリターンする。memqの文字‘q’は、この関数がobjectとリスト内の要素の比較にeqを使用することを示す。たとえば:

(memq 'b '(a b c b a))
     ⇒ (b c b a)
(memq '(2) '((1) (2)))    ; 2つの(2)eqである必要はない未定義; nil((2))かも
Function: delq object list

この関数はlistからobjecteqであるような、すべての要素を破壊的に取り除いて結果のリストをリターンする。delqの文字‘q’は、この関数がobjectとリスト内の要素の比較にeqを使用することを示す(memqremqと同様)。

delqを呼び出すときは、通常は元のリストを保持していた変数にリターン値を割り当てて使用する必要がある(理由は以下参照)。

delq関数がリストの先頭にある要素を削除する場合は、単にリストを読み進めてこの要素の後から開始される部分リストをリターンします。つまり:

(delq 'a '(a b c)) ≡ (cdr '(a b c))

リストの途中にある要素を削除するときは、必要なCDR (リストのCDRの変更を参照)を変更することで削除を行います。

(setq sample-list (list 'a 'b 'c '(4)))
     ⇒ (a b c (4))
(delq 'a sample-list)
     ⇒ (b c (4))
sample-list
     ⇒ (a b c (4))
(delq 'c sample-list)
     ⇒ (a b (4))
sample-list
     ⇒ (a b (4))

(delq 'a sample-list)は何も取り除きませんが(単に短いリストをリターンする)、(delq 'c sample-list)は3番目の要素を取り除いてsample-listを変更することに注意してください。引数listを保持するように形成された変数が、実行後にもっと少ない要素になるとか、元のリストを保持すると仮定しないでください! かわりにdelqの結果を保存して、それを使用してください。元のリストを保持していた変数に結果を書き戻すことはよく行なわれます。

(setq flowers (delq 'rose flowers))

以下の例では、delqが比較しようとしている(list 4)sample-list内の(4)は、equalですがeqではありません:

(delq (list 4) sample-list)
     ⇒ (a c (4))

与えられた値とequalな要素を削除したい場合には、delete (以下参照)を使用してください。

Function: remq object list

この関数はobjecteqなすべての要素が除かれた、listのコピーをリターンする。remqの文字‘q’は、この関数がobjectとリスト内の要素の比較にeqを使用することを示す。

(setq sample-list (list 'a 'b 'c 'a 'b 'c))
     ⇒ (a b c a b c)
(remq 'a sample-list)
     ⇒ (b c b c)
sample-list
     ⇒ (a b c a b c)
Function: memql object list

関数memqleql(浮動少数点数の要素は値で比較される)を使用してメンバーとeqlを比較することにより、objectlistのメンバーかどうかをテストする。objectがメンバーなら、memqllist内で最初に見つかった要素から始まるリスト、それ以外ならnilをリターンする。

memqと比較してみよう:

(memql 1.2 '(1.1 1.2 1.3))  ; 1.21.2eql
     ⇒ (1.2 1.3)
(memq 1.2 '(1.1 1.2 1.3))  ; 2つの1.2eqである必要はない未定義; nil(1.2 1.3)かもしれない

以下の3つの関数はmemqdelqremqと似ていますが、要素の比較にeqではなくequalを使用します。同等性のための述語を参照してください。

Function: member object list

関数memberは、メンバーとobjectequalを使用して比較して、objectlistのメンバーかどうかをテストする。objectがメンバーなら、memberlistで最初に見つかったところから開始されるリスト、それ以外ならnilをリターンする。

memqと比較してみよう:

(member '(2) '((1) (2)))  ; (2) and (2) are equal.
     ⇒ ((2))
(memq '(2) '((1) (2)))    ; 2つの(2)eqである必要はない未定義; nil(2)かもしれない
;; 同じ内容の2つの文字列はequal
(member "foo" '("foo" "bar"))
     ⇒ ("foo" "bar")
Function: delete object sequence

この関数はsequenceからobjectequalな要素を取り除いて、結果のシーケンスをリターンする。

sequenceがリストなら、deletedelqに対応するように、membermemqに対応する。つまりこの関数はmemberと同様、要素とobjectの比較にequalを使用する。マッチする要素が見つかったら、delqが行なうようにその要素を取り除く。delqと同様、通常は元のリストを保持していた変数にリターン値を割り当てて使用する。

sequenceがベクターか文字列なら、deleteobjectequalなすべての要素を取り除いたsequenceのコピーをリターンする。

たとえば:

(setq l (list '(2) '(1) '(2)))
(delete '(2) l)
     ⇒ ((1))
l
     ⇒ ((2) (1))
;; lの変更に信頼性を要するときは
;; (setq l (delete '(2) l))と記述する。
(setq l (list '(2) '(1) '(2)))
(delete '(1) l)
     ⇒ ((2) (2))
l
     ⇒ ((2) (2))
;; このケースではlのセットの有無に違い
;; はないが他のケースに倣ってセットするべき
(delete '(2) [(2) (1) (2)])
     ⇒ [(1)]
Function: remove object sequence

この関数はdeleteに対応する非破壊的な関数である。この関数はobjectequalな要素を取り除いた、sequence(リスト、ベクター、文字列)のコピーをリターンする。たとえば:

(remove '(2) '((2) (1) (2)))
     ⇒ ((1))
(remove '(2) [(2) (1) (2)])
     ⇒ [(1)]

Common Lispに関する注意: GNU Emacs Lispの関数memberdeleteremoveはCommon Lispではなく、Maclispを継承する。Common Lispでは比較にequalを使用しない。

Function: member-ignore-case object list

この関数はmemberと同様だが、objectが文字列でcaseとテキスト表現の違いを無視する。文字の大文字と小文字は等しいものとして扱われ、比較に先立ちユニバイト文字列はマルチバイト文字列に変換される。

Function: delete-dups list

この関数はlistからすべてのequalな重複を破壊的に取り除いて、結果をlistに保管してそれをリターンする。list内の要素にequalな要素がいくつかあるなら、delete-dupsは最初の要素を残す。

変数に格納されたリストへの要素の追加や、それを集合として使用する方法については、リスト変数の変更の関数add-to-listも参照してください。


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

5.8 連想リスト

連想配列(association list、短くはalist)は、キーと値のマッピングを記録します。これは連想(associations)と呼ばれるコンスセルのリストです。各コンスセルにおいてCARキー(key)で、CDR連想値(associated value)となります。5

以下はalistの例です。キーpineは値cones、キーoakacorns、キーmapleseedsに関連付けられます。

((pine . cones)
 (oak . acorns)
 (maple . seeds))

alist内の値とキーには、任意のLispオブジェクトを指定できます。たとえば以下のalist0では、シンボルaは数字1、文字列"b"リスト(2 3)(alist要素のCDR)に関連付けられます。

((a . 1) ("b" 2 3))

要素のCDRCARに連想値を格納するようにalistデザインするほうがよい場合があります。以下はそのようなalistです。

((rose red) (lily white) (buttercup yellow))

この例では、redroseに関連付けられる値だと考えます。この種のalistの利点は、CDRCDRの中に他の関連する情報 — 他のアイテムのリストでさえも — を格納することができることです。不利な点は、与えられた値を含む要素を見つけるためにrassq(以下参照)を使用できないことです。これらを検討することが重要でない場合には、すべての与えられたalistにたいして一貫している限り、選択は好みの問題といえます。

上記で示したのと同じalistは、要素のCDRに連想値をもつと考えることができます。この場合、roseに関連付けられる値はリスト(red)になるでしょう。

連想リストは新しい連想値を簡単にリストの先頭に追加できるので、スタックに保持したいような情報を記録するのによく使用されます。連想リストから与えられたキーにたいして連想値を検索する場合、それが複数ある場合は、最初に見つかったものがreturnされます。

Emacs Lispでは、連想リストがコンスセルでなくても、それはエラーではありません。alist検索関数は、単にそのような要素を無視します。多くの他のバージョンのLispでは、このような場合はエラーをシグナルします。

いくつかの観点において、プロパティーリストは連想リストと似ていることに注意してください。それぞれのキーが一度だけ出現するような場合、プロパティーリストは連想リストと同様に振る舞います。プロパティーリストと連想リストの比較については、プロパティリストを参照してください。

Function: assoc key alist &optional testfn

この関数はalist要素にたいして非nilならtestfn、それ以外ならを使用して、alist内からkeyをもつ最初の連想をリターンする。CARkeyequalであるような連想値がalistになければ、この関数はnilをリターンする。たとえば:

(setq trees '((pine . cones) (oak . acorns) (maple . seeds)))
     ⇒ ((pine . cones) (oak . acorns) (maple . seeds))
(assoc 'oak trees)
     ⇒ (oak . acorns)
(cdr (assoc 'oak trees))
     ⇒ acorns
(assoc 'birch trees)
     ⇒ nil

以下はキーと値がシンボルでない場合の例である:

(setq needles-per-cluster
      '((2 "Austrian Pine" "Red Pine")
        (3 "Pitch Pine")
        (5 "White Pine")))

(cdr (assoc 3 needles-per-cluster))
     ⇒ ("Pitch Pine")
(cdr (assoc 2 needles-per-cluster))
     ⇒ ("Austrian Pine" "Red Pine")

関数assoc-stringassocと似ていますが、文字列間の特定の違いを無視する点が異なります。文字および文字列の比較を参照してください。

Function: rassoc value alist

この関数はalistの中から値valueをもつ最初の連想をリターンする。CDRvalueequalであるような連想値がalistになければ、この関数はnilをリターンする。

rassocassocと似てイルが、CARではなくalistの連想値のCDRを比較する。この関数は与えられた値に対応するキーを探す、assocの逆バージョンと考えることができよう。

Function: assq key alist

この関数はalistからkeyをもつ最初の連想値をリターンする点はassocと同様だが、比較にeqを使用する点が異なる。CARkeyeqであるような連想値がalist内に存在しなければassqnilをリターンする。eqequalより高速であり、ほとんどのalistはキーにシンボルを使用するので、この関数はassocより多用される。同等性のための述語を参照のこと。

(setq trees '((pine . cones) (oak . acorns) (maple . seeds)))
     ⇒ ((pine . cones) (oak . acorns) (maple . seeds))
(assq 'pine trees)
     ⇒ (pine . cones)

逆にキーがシンボルではないalistでは、通常はassqは有用ではない:

(setq leaves
      '(("simple leaves" . oak)
        ("compound leaves" . horsechestnut)))

(assq "simple leaves" leaves)
     ⇒ 未定義; nil("simple leaves" . oak)かもしれない
(assoc "simple leaves" leaves)
     ⇒ ("simple leaves" . oak)
Function: alist-get key alist &optional default remove testfn

この関数はassqと似ている。これはalistの要素のkeyを比較して最初の連想(key . value)を見つける。連想が見つからなければ、関数はdefaultをリターンする。alistにたいするkeyの比較にはtestfnで指定された関数を使用する(デフォルトはeq)。

これはsetfでの値の変更に使用できる汎変数(ジェネリック変数を参照)。値の値へのセットにこれを使用する際にオプション引数removenilの場合は、新たな値がdefaulteqlならalistからkeyの連想を削除することを意味する。

Function: rassq value alist

この関数は、alist内から値valueをもつ最初の連想値をリターンする。alist内にCDRvalueeqであるような連想値が存在しないならnilをリターンする。

rassqassqと似ていますが、CARではなくalistの各連想のCDRを比較します。この関数を、与えられた値に対応するキーを探すassqの逆バージョンと考えることができます。

たとえば:

(setq trees '((pine . cones) (oak . acorns) (maple . seeds)))

(rassq 'acorns trees)
     ⇒ (oak . acorns)
(rassq 'spores trees)
     ⇒ nil

rassqは要素のCDRCARに保管された値の検索はできません:

(setq colors '((rose red) (lily white) (buttercup yellow)))

(rassq 'white colors)
     ⇒ nil

この場合、連想(lily white)CDRwhiteではなくリスト(white)です。これは連想をドットペア表記で記述すると明確になります:

(lily white) ≡ (lily . (white))
Function: assoc-default key alist &optional test default

この関数は、keyにたいするマッチをalistから検索する。alistの各要素にたいして、この関数はkeyと要素(アトムの場合)、または要素のCAR(コンスの場合)を比較する。比較はtestに2つの引数 — 要素(か要素のCAR)とkey — を与えて呼び出すことにより行なわれる。引数はこの順番で渡されるので、正規表現(正規表現の検索を参照)を含むalistでは、string-matchを使用することにより有益な結果を得ることができる。testが省略またはnilなら比較にequalが使用される。

alistの要素がこの条件によりkeyとマッチすると、assoc-defaultはその要素の値をリターンする。要素がコンスなら値は要素のCDR、それ以外ならリターン値はdefaultとなる。

keyにマッチする要素がalistに存在しないければ、assoc-defaultnilをリターンする。

Function: copy-alist alist

この関数は深さのレベルが2のalistのコピーをリターンする。この関数は各連想の新しいコピーを作成するので、元のalistを変更せずに新しいalistを変更できる。

(setq needles-per-cluster
      '((2 . ("Austrian Pine" "Red Pine"))
        (3 . ("Pitch Pine"))
        (5 . ("White Pine"))))
⇒
((2 "Austrian Pine" "Red Pine")
 (3 "Pitch Pine")
 (5 "White Pine"))

(setq copy (copy-alist needles-per-cluster))
⇒
((2 "Austrian Pine" "Red Pine")
 (3 "Pitch Pine")
 (5 "White Pine"))

(eq needles-per-cluster copy)
     ⇒ nil
(equal needles-per-cluster copy)
     ⇒ t
(eq (car needles-per-cluster) (car copy))
     ⇒ nil
(cdr (car (cdr needles-per-cluster)))
     ⇒ ("Pitch Pine")
(eq (cdr (car (cdr needles-per-cluster)))
    (cdr (car (cdr copy))))
     ⇒ t

以下の例は、どのようにしてcopy-alistが他に影響を与えずにコピーの連想を変更可能なのかを示す:

(setcdr (assq 3 copy) '("Martian Vacuum Pine"))
(cdr (assq 3 needles-per-cluster))
     ⇒ ("Pitch Pine")
Function: assq-delete-all key alist

この関数は、delqを使用してマッチする要素を1つずつ削除するときのように、CARkeyeqであるようなすべての要素をalistから削除する。この関数は短くなったalistをリターンし、alistの元のリスト構造を変更することもよくある。正しい結果を得るために、alistに保存された値ではなくassq-delete-allのリターン値を使用すること。

(setq alist (list '(foo 1) '(bar 2) '(foo 3) '(lose 4)))
     ⇒ ((foo 1) (bar 2) (foo 3) (lose 4))
(assq-delete-all 'foo alist)
     ⇒ ((bar 2) (lose 4))
alist
     ⇒ ((foo 1) (bar 2) (lose 4))
Function: assoc-delete-all key alist &optional test

この関数はassq-delete-allと同様だが、オプション引数test ( alist内のキーを比較するための述語関数)を受け取る点が異なる。testが省略かnilならデフォルトはequal。この関数はassq-delete-allのように、多くの場合はalistの元のリスト構造を変更する。

Function: rassq-delete-all value alist

この関数は、alistからCDRvalueeqであるようなすべての要素を削除する。この関数は短くなったリストをリターンし、alistの元のリスト構造を変更することもよくある。rassq-delete-allassq-delete-allと似ているが、CARではなくalistの各連想のCDRを比較する。

Macro: let-alist alist body

連想リストalistのキーとして使用される先頭にドットを付したシンボルそれぞれにたいしてバインディングを作成する。これは同じ連想リスト内の複数のアイテムにアクセスする際に有用かもしれない。理解するためにもっともよいのは以下のシンプルな例だろう:

(setq colors '((rose . red) (lily . white) (buttercup . yellow)))
(let-alist colors
  (if (eq .rose 'red)
      .lily))
=> white

bodyをコンパイル時に検査して、body内に出現する先頭文字として‘.’を付したシンボルだけがバインドされる。キーの検索はassq、このassqのリターン値のcdrがそのバインディングにたいする値として割り当てられる。

ネストされた連想リストをサポートする:

(setq colors '((rose . red) (lily (belladonna . yellow) (brindisi . pink))))
(let-alist colors
  (if (eq .rose 'red)
      .lily.belladonna))
=> yellow

互いに内部にlet-alistをネストすることが可能だが、内側のlet-alistは外側のlet-alistがバインドする変数にはアクセスできない。


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

5.9 プロパティリスト

プロパティーリスト(property list、短くはplist)は、ペアになった要素のリストです。各ペアはプロパティー名(通常はシンボル)とプロパティー値を対応づけます。以下はプロパティーリストの例です:

(pine cones numbers (1 2 3) color "blue")

このプロパティーリストはpineconesnumbers(1 2 3)color"blue"に関連づけます。プロパティー名とプロパティー値には任意のLispオブジェクトを指定できますが、通常プロパティー名は(この例のように)シンボルです。

いくつかのコンテキストでプロパティーリストが使用されます。たとえば関数put-text-propertyはプロパティーリストを引数にとり、文字列やバッファー内のテキストにたいして、テキストプロパティーとテキストに適用するプロパティー値を指定します。テキストのプロパティを参照してください。

プロパティーリストが頻繁に使用される他の例は、シンボルプロパティーの保管です。すべてのシンボルはシンボルに関する様々な情報を記録するために、プロパティーのリストを処理します。これらのプロパティーはプロパティーリストの形式で保管されます。シンボルのプロパティを参照してください。


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

5.9.1 プロパティリストと連想リスト

連想リスト(連想リストを参照)は、プロパティーリストとよく似ています。連想リストとは対照的にプロパティー名は一意でなければならないので、プロパティーリスト内でペアの順序に意味はありません。

様々なLisp関数や変数に情報を付加するためには、連想リストよりプロパティーリストの方が適しています。プログラムでこのような情報すべてを1つの連想リストに保持する場合は、特定のLisp関数や変数にたいする連想をチェックする度にリスト全体を検索する必要が生じ、それにより遅くなる可能性があります。対照的に関数名や変数自体のプロパティーリストに同じ情報を保持すれば、検索ごとにそのプロパティーリストの長さだけを検索するようになり、通常はこちらの方が短時間で済みます。変数のドキュメントがvariable-documentationという名前のプロパティーに記録されているのはこれが理由です。同様にバイトコンパイラーも、特別に扱う必要がある関数を記録するためにプロパティーを使用します。

とはいえ連想リストにも独自の利点があります。アプリケーションに依存しますが、プロパティーを更新するより連想リストの先頭に連想を追加する方が高速でしょう。シンボルにたいするすべてのプロパティーは同じプロパティーリストに保管されるので、プロパティー名を異なる用途のために使用すると衝突の可能性があります(この理由により、そのプログラムで通常の変数や関数の名前につけるプレフィクスをプロパティー名の先頭につけて、一意と思われるプロパティー名を選ぶのはよいアイデアだと言える)。連想リストは、連想をリストの先頭にpushして、その後にある連想は無視されるので、スタックと同様に使用できます。これはプロパティーリストでは不可能です。


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

5.9.2 プロパティリストと外部シンボル

以下の関数はプロパティーリストを操作するために使用されます。これらの関数はすべて、プロパティー名の比較にeqを使用します。

Function: plist-get plist property

この関数はプロパティーリストplistに保管された、プロパティーpropertyの値をリターンする。この関数には不正な形式(malformed)のplist引数を指定できる。plistpropertyが見つからないと、この関数はnilをリターンする。たとえば、

(plist-get '(foo 4) 'foo)
     ⇒ 4
(plist-get '(foo 4 bad) 'foo)
     ⇒ 4
(plist-get '(foo 4 bad) 'bad)
     ⇒ nil
(plist-get '(foo 4 bad) 'bar)
     ⇒ nil
Function: plist-put plist property value

この関数はプロパティーリストplistに、プロパティーpropertyの値としてvalueを保管する。この関数はplistを破壊的に変更するかもしれず、元のリスト構造を変更せずに新しいリストを構築することもある。この関数は変更されたプロパティーリストをリターンするので、plistを取得した場所に書き戻すことができる。たとえば、

(setq my-plist (list '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)))
     ⇒ (bar t foo 69 quux (a))
Function: lax-plist-get plist property

plist-getと同様だがプロパティーの比較にeqではなくequalを使用する。

Function: lax-plist-put plist property value

plist-putと同様だがプロパティーの比較にeqではなくequalを使用する。

Function: plist-member plist property

この関数は与えられたpropertyplistに含まれるなら非nilをリターンする。plist-getとは異なりこの関数は存在しないプロパティーと、値がnilのプロパティーを区別できる。実際にリターンされる値は、carpropertyで始まるplistの末尾部分である。


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

6 シーケンス、配列、ベクター

シーケンス(sequence)型は2つの異なるLisp型 — リストと配列 — を結合した型です。言い換えると任意のリストはシーケンスであり任意の配列はシーケンスです。すべてのシーケンスがもつ共通な属性は、それぞれが順序づけされた要素のコレクションであることです。

配列(array)はスロットがその要素であるような、固定長のオブジェクトです。すべての要素に一定時間でアクセスできます。配列の4つの型として文字列、ベクター、文字テーブル、ブールベクターがあります。

リストは要素のシーケンスですが、要素は単一の基本オブジェクトではありません。リストはコンスセルにより作られ、要素ごとに1つのセルをもちます。n番目の要素を探すにはn個のコンスセルを走査する必要があるので、先頭から離れた要素ほどアクセスに時間を要します。しかしリストは要素の追加や削除が可能です。

以下の図はこれらの型の関連を表しています:

          _____________________________________________
         |                                             |
         |          Sequence                           |
         |  ______   ________________________________  |
         | |      | |                                | |
         | | List | |             Array              | |
         | |      | |    ________       ________     | |
         | |______| |   |        |     |        |    | |
         |          |   | Vector |     | String |    | |
         |          |   |________|     |________|    | |
         |          |  ____________   _____________  | |
         |          | |            | |             | | |
         |          | | Char-table | | Bool-vector | | |
         |          | |____________| |_____________| | |
         |          |________________________________| |
         |_____________________________________________|

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

6.1 シーケンス

このセクションでは任意の種類のシーケンスを許す関数を説明します。

Function: sequencep object

この関数はobjectがリスト、ベクター、文字列、ブールベクター、文字テーブルならt、それ以外はnilをリターンする。以下のseqpも参照のこと。

Function: length sequence

この関数はsequence内の要素の数をリターンする。sequenceがシーケンス以外、またはドットリストならwrong-type-argumentエラーをシグナルする。引数が循環リストならcircular-listエラーをシグナルする。文字テーブルではEmacsの最大文字コードより1大きい値が常にリターンされる。

関連する関数safe-lengthについてはDefinition of safe-lengthを参照のこと。

(length '(1 2 3))
    ⇒ 3
(length ())
    ⇒ 0
(length "foobar")
    ⇒ 6
(length [1 2 3])
    ⇒ 3
(length (make-bool-vector 5 nil))
    ⇒ 5

テキストの表現方法string-bytesも参照されたい。

ディスプレー上での文字列の幅を計算する必要があるなら、文字数だけを数えて各文字のディスプレー幅を計算しないlengthではなく、string-width (表示されるテキストのサイズを参照)を使用すること。

Function: elt sequence index

この関数はindexによりインデックスづけされた、sequenceの要素をリターンする。indexの値として妥当なのは、0からsequenceの長さより1小さい数までの範囲の整数。sequenceがリストなら範囲外の値はnthと同じように振る舞う。Definition of nthを参照のこと。それ以外なら範囲外の値はargs-out-of-rangeエラーを引き起こす。

(elt [1 2 3 4] 2)
     ⇒ 3
(elt '(1 2 3 4) 2)
     ⇒ 3
;; eltがどの文字をreturnするか明確にするためにstringを使用
(string (elt "1234" 2))
     ⇒ "3"
(elt [1 2 3 4] 4)
     error→ Args out of range: [1 2 3 4], 4
(elt [1 2 3 4] -1)
     error→ Args out of range: [1 2 3 4], -1

この関数はaref (配列を操作する関数を参照)とnth (Definition of nthを参照)を一般化したものである。

Function: copy-sequence seqr

この関数はseqr (シーケンスかレコードであること)のコピーをリターンする。コピーはオリジナルと同じオブジェクト型であり、同じ要素を同じ順序でもつ。しかしseqrが空なら長さが0の文字列やベクターと同じように関数がリターンする値はコピーではないかもしれないが、seqrと同じ型の空のオブジェクトである。

コピーに新しい要素を格納するのは元のseqrに影響を与えずその逆も真である。しかし新しいシーケンス内の要素はコピーではなく、元のシーケンスの要素と同一(eq)になる。したがってコピーされたシーケンスを介して見つかった要素を変更するとオリジナルでも変更を見ることができる。

引数がテキストプロパティーをもつ文字列なら、コピー内のプロパティーリスト自身もコピーとなり、元のシーケンスのプロパティーリストと共有はされない。しかしプロパティーリストの実際の値は共有される。テキストのプロパティを参照のこと。

この関数はドットリストでは機能しない。循環リストのコピーは無限ループを起こすだろう。

シーケンスをコピーする別の方法についてはコンスセルおよびリストの構築append文字列の作成concatベクターのための関数vconcatも参照されたい。

(setq bar (list 1 2))
     ⇒ (1 2)
(setq x (vector 'foo bar))
     ⇒ [foo (1 2)]
(setq y (copy-sequence x))
     ⇒ [foo (1 2)]

(eq x y)
     ⇒ nil
(equal x y)
     ⇒ t
(eq (elt x 1) (elt y 1))
     ⇒ t

;; 一方のシーケンスの要素を置き換え
(aset x 0 'quux)
x ⇒ [quux (1 2)]
y ⇒ [foo (1 2)]

;; 共有された要素の内部を変更
(setcar (aref x 1) 69)
x ⇒ [quux (69 2)]
y ⇒ [foo (69 2)]
Function: reverse sequence

この関数はsequenceの要素を反転した要素をもつ新たなシーケンスを作成する。元となる引数sequence変更されない。文字テーブルは反転できないことに注意。

(setq x '(1 2 3 4))
     ⇒ (1 2 3 4)
(reverse x)
     ⇒ (4 3 2 1)
x
     ⇒ (1 2 3 4)
(setq x [1 2 3 4])
     ⇒ [1 2 3 4]
(reverse x)
     ⇒ [4 3 2 1]
x
     ⇒ [1 2 3 4]
(setq x "xyzzy")
     ⇒ "xyzzy"
(reverse x)
     ⇒ "yzzyx"
x
     ⇒ "xyzzy"
Function: nreverse sequence

この関数はsequenceの要素を反転する。reverseとは異なり、元となるsequenceは変更されるかもしれない。

たとえば:

(setq x (list 'a 'b 'c))
     ⇒ (a b c)
x
     ⇒ (a b c)
(nreverse x)
     ⇒ (c b a)
;; 先頭にあったコンスセルが末尾となった
x
     ⇒ (a)

混乱しないように、通常は元となるリストを保持する同じ変数に、nreverseの結果を書き戻す:

(setq x (nreverse x))

お馴染の例(a b c)nreverseを以下に図示する:

Original list head:                       Reversed list:
 -------------        -------------        ------------
| car  | cdr  |      | car  | cdr  |      | car | cdr  |
|   a  |  nil |<--   |   b  |   o  |<--   |   c |   o  |
|      |      |   |  |      |   |  |   |  |     |   |  |
 -------------    |   --------- | -    |   -------- | -
                  |             |      |            |
                   -------------        ------------

setqが不要なのでベクターはより単純になる:

(setq x (copy-sequence [1 2 3 4]))
     ⇒ [1 2 3 4]
(nreverse x)
     ⇒ [4 3 2 1]
x
     ⇒ [4 3 2 1]

reverseとは異なり、この関数は文字列では機能しない。asetを使用して文字列データを変更できても、たとえmutableであったとしても文字列は不変として扱うことを強く推奨する。可変性を参照のこと。

Function: sort sequence predicate

この関数はsequenceを安定ソートする。この関数はすべてのシーケンスにたいしては機能せず、リストとベクターにたいしてのみ使用できることに注意されたい。sequenceがリストなら破壊的に変更される。この関数はソートされたsequenceをリターンして、要素の比較にはpredicateを使用する。安定ソートでは、ソートキーが等しい要素の相対順序がソートの前後で保たれる。この安定性は異なる条件により要素を並べ替えるために、連続してソートを行う場合に重要となる。

引数predicateは2つの引数を受け取る関数でなければならない。これはsequenceの2つの要素で呼び出される。昇順でソートするなら、1つ目の要素が2つ目の要素より“小”なら非nil、それ以外ならnilをリターンすること。

比較関数predicateは、少なくともsortの単一の呼び出しにおいて、与えられた任意の引数ペアにたいして信頼できる結果をリターンしなければならない。これは非対照的(antisymmetric)、すなわちabより小なら、baより小であってはならず、推移律(transitive)、すなわちabより小、かつbcより小なら、acより小でなければならない。これらの要件に合致しない比較関数を使用すると、sortの結果は予想できない。

sortのリストにたいする破壊的側面は、CDRを変更することによりsequenceを形成するコンスセルを再配置することにある。非破壊ソート関数は、それらのソート順に要素を格納するために、新たなコンスセルを作成するだろう。オリジナルを破壊せずにソートしたコピーを望むなら、まずcopy-sequenceでコピーしてからソートすること。

ソートによりsequenceのコンスセルのCARは変化しない。元々sequence内で要素aを含むコンスセルは、ソート後もそのCARaを保持する。しかしCDRの変更により、ソート後には異なる位置に出現する。たとえば:

(setq nums (list 1 3 2 6 5 4 0))
     ⇒ (1 3 2 6 5 4 0)
(sort nums #'<)
     ⇒ (0 1 2 3 4 5 6)
nums
     ⇒ (1 2 3 4 5 6)

警告 nums内のリストが0を含まないことに注意。これはソート前と同じコンスセルだがもはやリストの先頭ではない。ソート前に引数を保持していた変数がソート済みリスト全体を保持すると仮定してはならない! かわりにsortの結果を保存して、それを使うこと。ほとんどの場合、わたしたちは元のリストを保持していた変数に結果を書き戻すようにしている。

(setq nums (sort nums #'<))

安定ソートの何たるかをより理解するには、以下のベクターのサンプルを考えてみよ。ソート後、carが8であるようなすべてのアイテムはvectorの先頭にグループ化されるが、それらの相対的な順序は保たれる。carが9であるようなすべてのアイテムはvectorの末尾にグループ化されるが、それらの相対的な順序も保たれる。

(setq
  vector
  (vector '(8 . "xxx") '(9 . "aaa") '(8 . "bbb") '(9 . "zzz")
          '(9 . "ppp") '(8 . "ttt") '(8 . "eee") '(9 . "fff")))
     ⇒ [(8 . "xxx") (9 . "aaa") (8 . "bbb") (9 . "zzz")
         (9 . "ppp") (8 . "ttt") (8 . "eee") (9 . "fff")]
(sort vector (lambda (x y) (< (car x) (car y))))
     ⇒ [(8 . "xxx") (8 . "bbb") (8 . "ttt") (8 . "eee")
         (9 . "aaa") (9 . "zzz") (9 . "ppp") (9 . "fff")]

ソートを行う他の関数についてはテキストのソートを参照のこと。sortの有用な例は、ドキュメント文字列へのアクセスdocumentationを参照されたい。

seq.elライブラリーは、以下のようなプレフィクスseq-がついたシーケンス操作用の追加のマクロと関数を提供します。それらを使用するには、最初にseqライブラリーをロードしなければなりません。

このライブラリー内で定義されたすべての関数は、副作用をもちません。これらは引数として渡されたすべてのシーケンス(リスト、ベクター、文字列)を変更しません。特に明記しなければ、結果は入力と同じ型のシーケンスです。述語を受け取る関数では、それらは単一の関数である必要があります。

seq.elライブラリーは、シーケンシャルなデータ構造の追加型で機能するように拡張可能です。そのためにすべての関数はcl-defgenericを使用して定義されています。cl-defgenericを使用した拡張の追加に関する詳細は、ジェネリック関数を参照してください。

Function: seq-elt sequence index

この関数はindex(有効な範囲は0からsequenceの長さより1少ない整数)で指定されたsequenceの要素をリターンする。ビルトインのシーケンス型にたいする範囲外(out-of-range)の値にたいして、seq-elteltと同様に振る舞う。詳細はDefinition of eltを参照のこと。

(seq-elt [1 2 3 4] 2)
⇒ 3

seq-eltsetfを使用してセット可能なplaceをリターンする(setfマクロを参照)。

(setq vec [1 2 3 4])
(setf (seq-elt vec 2) 5)
vec
⇒ [1 2 5 4]
Function: seq-length sequence

この関数はsequence内の要素の個数をリターンする。ビルトインのシーケンス型にたいしてseq-lengthlengthと同様に振る舞う。Definition of lengthを参照のこと。

Function: seqp object

この関数はobjectがシーケンス(リストか配列)、またはseq.elのジェネリック関数を通じて定義されたすべての追加シーケンス型なら非nilをリターンする。これはsequencepの拡張された変種である。

(seqp [1 2])
⇒ t
(seqp 2)
⇒ nil
Function: seq-drop sequence n

この関数はsequenceの最初のn個(整数)を除く、すべての要素をリターンする.nが0以下なら結果はsequence

(seq-drop [1 2 3 4 5 6] 3)
⇒ [4 5 6]
(seq-drop "hello world" -4)
⇒ "hello world"
Function: seq-take sequence n

この関数はsequenceの最初のn個(整数)の要素をリターンする。nが0以下なら結果はnil

(seq-take '(1 2 3 4) 3)
⇒ (1 2 3)
(seq-take [1 2 3 4] 0)
⇒ []
Function: seq-take-while predicate sequence

この関数はsequenceのメンバーを順にリターンし、predicateが最初にnilをリターンした要素の前で停止する。

(seq-take-while (lambda (elt) (> elt 0)) '(1 2 3 -1 -2))
⇒ (1 2 3)
(seq-take-while (lambda (elt) (> elt 0)) [-1 4 6])
⇒ []
Function: seq-drop-while predicate sequence

この関数はpredicateが最初にnilをリターンした要素から、sequenceのメンバーを順にリターンする。

(seq-drop-while (lambda (elt) (> elt 0)) '(1 2 3 -1 -2))
⇒ (-1 -2)
(seq-drop-while (lambda (elt) (< elt 0)) [1 4 6])
⇒ [1 4 6]
Function: seq-do function sequence

この関数はsequenceの各要素にたいして、(恐らくは副作用を得るために)順番にfunctionを適用して、sequenceをリターンする。

Function: seq-map function sequence

この関数はsequenceの各要素にfunctionを適用した結果をリターンする。リターン値はリスト。

(seq-map #'1+ '(2 4 6))
⇒ (3 5 7)
(seq-map #'symbol-name [foo bar])
⇒ ("foo" "bar")
Function: seq-map-indexed function sequence

この関数はsequenceの各要素およびseqであるようなインデックスにfunctionを適用した結果をリターンする。リターン値はリスト。

(seq-map-indexed (lambda (elt idx)
                   (list idx elt))
                 '(a b c))
⇒ ((0 a) (b 1) (c 2))
Function: seq-mapn function &rest sequences

この関数はsequencesの各要素にfunctionを適用した結果をリターンする。 functionのarity (関数が受け取れる引数の個数。subr-arityを参照)はシーケンスの個数にマッチしなければならない。マッピングは最短のシーケンス終端で停止する。リターン値はリスト。

(seq-mapn #'+ '(2 4 6) '(20 40 60))
⇒ (22 44 66)
(seq-mapn #'concat '("moskito" "bite") ["bee" "sting"])
⇒ ("moskitobee" "bitesting")
Function: seq-filter predicate sequence

この関数はpredicateが非nilをリターンしたsequence内のすべての要素のリストをリターンする。

(seq-filter (lambda (elt) (> elt 0)) [1 -1 3 -3 5])
⇒ (1 3 5)
(seq-filter (lambda (elt) (> elt 0)) '(-1 -3 -5))
⇒ nil
Function: seq-remove predicate sequence

この関数はpredicatenilをリターンしたsequence内のすべての要素のリストをリターンする。

(seq-remove (lambda (elt) (> elt 0)) [1 -1 3 -3 5])
⇒ (-1 -3)
(seq-remove (lambda (elt) (< elt 0)) '(-1 -3 -5))
⇒ nil
Function: seq-reduce function sequence initial-value

この関数はinitial-valuesequenceの1つ目の要素でfunctionを呼び出し、次にその結果とsequenceの2つ目の要素でfunctionを呼び出し、その次にその結果とsequenceの3つ目の要素で、...と呼び出した結果をリターンする。functionは引数が2つの関数であること。sequenceが空なら、これはfunctionを呼び出さずにinitial-valueをリターンする。

(seq-reduce #'+ [1 2 3 4] 0)
⇒ 10
(seq-reduce #'+ '(1 2 3 4) 5)
⇒ 15
(seq-reduce #'+ '() 3)
⇒ 3
Function: seq-some predicate sequence

この関数はsequenceの各要素に順にpredicateを適用してリターンされた、最初の非nil値をリターンする。

(seq-some #'numberp ["abc" 1 nil])
⇒ t
(seq-some #'numberp ["abc" "def"])
⇒ nil
(seq-some #'null ["abc" 1 nil])
⇒ t
(seq-some #'1+ [2 4 6])
⇒ 3
Function: seq-find predicate sequence &optional default

この関数はpredicateが非nilをリターンした、sequence内の最初の要素をリターンする。predicateにマッチする要素がなければ、この関数はdefaultをリターンする。

この関数は見つかった要素がdefaultと等しい場合、要素が見つかったかどうかを知る術がないので曖昧さをもつことに注意。

(seq-find #'numberp ["abc" 1 nil])
⇒ 1
(seq-find #'numberp ["abc" "def"])
⇒ nil
Function: seq-every-p predicate sequence

この関数はsequenceの各要素にpredicateを適用して、すべてが非nilをリターンしたら非nilをリターンする。

(seq-every-p #'numberp [2 4 6])
⇒ t
(seq-every-p #'numberp [2 4 "6"])
⇒ nil
Function: seq-empty-p sequence

この関数はsequenceが空ならnilをリターンする。

(seq-empty-p "not empty")
⇒ nil
(seq-empty-p "")
⇒ t
Function: seq-count predicate sequence

この関数はsequence内でpredicateが非nilをリターンした要素の個数をリターンする。

(seq-count (lambda (elt) (> elt 0)) [-1 2 0 3 -2])
⇒ 2
Function: seq-sort function sequence

この関数はfunctionに応じてソートされたsequenceのコピーをリターンする。functionは2つの引数を受け取り、1つ目の引数が2つ目より前にソートされるべきなら非nilをリターンする。

Function: seq-sort-by function predicate sequence

この関数はseq-sortと似ているがソート前にsequenceの要素にfunctionを適用して変換する点が異なる。functionは単一の引数を受け取る関数。

(seq-sort-by #'seq-length #'> ["a" "ab" "abc"])
⇒ ["abc" "ab" "a"]
Function: seq-contains-p sequence elt &optional function

この関数はsequence内の少なくとも1つの要素がeltとequalなら非nilをリターンする。オプション引数functionが非nilなら、それはデフォルトのequalのかわりに使用する2つの引数を受け取る関数であること。

(seq-contains '(symbol1 symbol2) 'symbol1)
⇒ symbol1
(seq-contains '(symbol1 symbol2) 'symbol3)
⇒ nil
Function: seq-set-equal-p sequence1 sequence2 &optional testfn

この関数は順序とは無関係にsequence1sequence2が同じ要素を含むかどうかをチェックする。オプション引数testfnが非nilなら、デフォルトのequalのかわりに使用する2つの引数を受け取る関数であること。

(seq-set-equal-p '(a b c) '(c b a))
⇒ t
(seq-set-equal-p '(a b c) '(c b))
⇒ nil
(seq-set-equal-p '("a" "b" "c") '("c" "b" "a"))
⇒ t
(seq-set-equal-p '("a" "b" "c") '("c" "b" "a") #'eq)
⇒ nil
Function: seq-position sequence elt &optional function

この関数はeltequalであるようなsequence内の最初の要素のインデックスをリターンする。オプション引数functionが非nilなら、それはデフォルトのequalのかわりに使用する2つの引数を受け取る関数であること。

(seq-position '(a b c) 'b)
⇒ 1
(seq-position '(a b c) 'd)
⇒ nil
Function: seq-uniq sequence &optional function

この関数は重複を削除したsequenceの要素のリストをリターンする。オプション引数functionが非nilなら、それはデフォルトのequalのかわりに使用する2つの引数を受け取る関数であること。

(seq-uniq '(1 2 2 1 3))
⇒ (1 2 3)
(seq-uniq '(1 2 2.0 1.0) #'=)
⇒ (1 2)
Function: seq-subseq sequence start &optional end

この関数はsequencestartからend(いずれも整数)までのサブセットをリターンする(endのデフォルトは最後の要素)。startendが負ならsequenceの最後から数える。

(seq-subseq '(1 2 3 4 5) 1)
⇒ (2 3 4 5)
(seq-subseq '[1 2 3 4 5] 1 3)
⇒ [2 3]
(seq-subseq '[1 2 3 4 5] -3 -1)
⇒ [3 4]
Function: seq-concatenate type &rest sequences

この関数はsequencesを結合して作成されたtype型のシーケンスをリターンする。typevectorliststringのいずれか。

(seq-concatenate 'list '(1 2) '(3 4) [5 6])
⇒ (1 2 3 4 5 6)
(seq-concatenate 'string "Hello " "world")
⇒ "Hello world"
Function: seq-mapcat function sequence &optional type

この関数はsequenceの各要素にfunctionを適用した結果に、seq-concatenateを適用した結果をリターンする。結果はtype型のシーケンス、またはtypenilならリストである。

(seq-mapcat #'seq-reverse '((3 2 1) (6 5 4)))
⇒ (1 2 3 4 5 6)
Function: seq-partition sequence n

この関数は長さnのサブシーケンスへグループ化したsequenceの要素のリストをリターンする。最後のシーケンスに含まれる要素はnより少ないかもしれない。nは整数であること。nが0以下の整数ならリターン値はnil

(seq-partition '(0 1 2 3 4 5 6 7) 3)
⇒ ((0 1 2) (3 4 5) (6 7))
Function: seq-intersection sequence1 sequence2 &optional function

この関数はsequence1sequence2の両方に出現する要素のリストをリターンする。オプション引数functionが非nilなら、それはデフォルトのequalのかわりに比較に使用する2つの引数を受け取る関数であること。

(seq-intersection [2 3 4 5] [1 3 5 6 7])
⇒ (3 5)
Function: seq-difference sequence1 sequence2 &optional function

この関数はsequence1に出現するがsequence2に出現しない要素のリストをリターンする。オプション引数functionが非nilなら、それはデフォルトのequalのかわりに比較に使用する2つの引数を受け取る関数であること。

(seq-difference '(2 3 4 5) [1 3 5 6 7])
⇒ (2 4)
Function: seq-group-by function sequence

この関数はsequenceの各要素にfunctionを適用して、その結果をキーとしてsequenceをalistに分割する。キーの比較にはequalを使用する。

(seq-group-by #'integerp '(1 2.1 3 2 3.2))
⇒ ((t 1 3 2) (nil 2.1 3.2))
(seq-group-by #'car '((a 1) (b 2) (a 3) (c 4)))
⇒ ((b (b 2)) (a (a 1) (a 3)) (c (c 4)))
Function: seq-into sequence type

この関数はシーケンスsequencetype型のシーケンスに変換する。typevectorstringlistのいずれかであること。

(seq-into [1 2 3] 'list)
⇒ (1 2 3)
(seq-into nil 'vector)
⇒ []
(seq-into "hello" 'vector)
⇒ [104 101 108 108 111]
Function: seq-min sequence

この関数はsequenceの最小の要素をリターンする。sequenceの要素は数字かマーカー(マーカーを参照)でなければならない。

(seq-min [3 1 2])
⇒ 1
(seq-min "Hello")
⇒ 72
Function: seq-max sequence

この関数はsequenceの最大の要素をリターンする。sequenceの要素は数字かマーカーでなければならない。

(seq-max [1 3 2])
⇒ 3
(seq-max "Hello")
⇒ 111
Macro: seq-doseq (var sequence) body…

このマクロはdolist (dolistを参照)と同様だが、sequenceにリスト、ベクター、文字列のいずれかを指定できる点が異なる。これ主な利点は副作用である。

Macro: seq-let var-sequence val-sequence body…

このマクロはvar-sequence内で定義される変数にval-sequenceの対応する要素をバインドする。これは分割代入(destructuring binding)として知られている。var-sequenceの要素は、ネストされた非構造化を許容することにより自身にシーケンスを含むことができる。

var-sequenceシーケンスには、val-sequenceの残りにバインドされる変数名が後続するような&restマーカーを含めることもできる。

(seq-let [first second] [1 2 3 4]
  (list first second))
⇒ (1 2)
(seq-let (_ a _ b) '(1 2 3 4)
  (list a b))
⇒ (2 4)
(seq-let [a [b [c]]] [1 [2 [3]]]
  (list a b c))
⇒ (1 2 3)
(seq-let [a b &rest others] [1 2 3 4]
  others)
⇒ [3 4]

pcaseパターンは分割代入にたいする代替えの機能を提供する。pcaseパターンによる分解を参照のこと。

Function: seq-random-elt sequence

この関数はsequenceの要素をランダムにリターンする。

(seq-random-elt [1 2 3 4])
⇒ 3
(seq-random-elt [1 2 3 4])
⇒ 2
(seq-random-elt [1 2 3 4])
⇒ 4
(seq-random-elt [1 2 3 4])
⇒ 2
(seq-random-elt [1 2 3 4])
⇒ 1

sequenceが空ならこの関数はエラーをシグナルする。


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

6.2 配列

配列(array)オブジェクトは、いくつかのLispオブジェクトを保持するスロットをもち、これらのオブジェクトは配列の要素と呼ばれます。配列内の任意の要素は一定時間でアクセスされます。対照的にリスト内の要素のアクセスに要する時間は、その要素がリスト内のどの位置にあるかに比例します。

Emacsは4つの配列型 —文字列(strings、文字列型を参照)ベクター(vectors、ベクター型を参照)ブールベクター(bool-vectors、ブールベクター型を参照)文字テーブル(char-tables、文字テーブル型を参照) — を定義しており、これらはすべて1次元です。ベクターと文字テーブルは任意の型の要素を保持できますが、文字列は文字だけ、ブールベクターはtnilしか保持できません。

4種のすべての配列はこれらの特性を共有します:

配列を作成したとき、文字テーブル以外では長さを指定しなければなりません。文字テーブルの長さは文字コードの範囲により決定されるので長さを指定できません。

原則として、テキスト文字の配列が欲しい場合は、文字列とベクターのどちらかを使用できます。実際のところ4つの理由により,そのような用途にたいしては、わたしたちは常に文字列を選択します:

対照的に、(キーシーケンスのような)キーボード入力文字の配列では、多くのキーボード入力文字は文字列に収まる範囲の外にあるので、ベクターが必要になるでしょう。キーシーケンス入力を参照してください。


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

6.3 配列を操作する関数

このセクションではすべての型の配列に適用される関数を説明します。

Function: arrayp object

この関数はobjectが配列(ベクター、文字列、ブールベクター、文字テーブル)ならtをリターンする。

(arrayp [a])
     ⇒ t
(arrayp "asdf")
     ⇒ t
(arrayp (syntax-table))    ;; 文字テーブル
     ⇒ t
Function: aref arr index

この関数はarr (配列かレコード)のindex番目の要素をリターンする。1番目の要素のインデクスは0。

(setq primes [2 3 5 7 11 13])
     ⇒ [2 3 5 7 11 13]
(aref primes 4)
     ⇒ 11
(aref "abcdefg" 1)
     ⇒ 98           ; b’のASCIIコードは98

シーケンスの関数eltも参照されたい。

Function: aset array index object

この関数はarrayindex番目の要素をobjectにセットする。この関数はobjectをリターンする。

(setq w (vector 'foo 'bar 'baz))
     ⇒ [foo bar baz]
(aset w 0 'fu)
     ⇒ fu
w
     ⇒ [fu bar baz]

;; copy-sequenceは後で変更する文字列をコピーする
(setq x (copy-sequence "asdfasfd"))
     ⇒ "asdfasfd"
(aset x 3 ?Z)
     ⇒ 90
x
     ⇒ "asdZasfd"

arrayはmutableであること。可変性を参照のこと。

arrayが文字列でobjectが文字でなければ、結果はwrong-type-argumentエラーとなる。この関数は文字列の挿入で必要なら、ユニバイト文字列をマルチバイト文字列に変換する。

Function: fillarray array object

この関数は配列arrayobjectで充填するので、arrayのすべての要素はobjectになる。この関数はarrayをリターンする。

(setq a (copy-sequence [a b c d e f g]))
     ⇒ [a b c d e f g]
(fillarray a 0)
     ⇒ [0 0 0 0 0 0 0]
a
     ⇒ [0 0 0 0 0 0 0]
(setq s (copy-sequence "When in the course"))
     ⇒ "When in the course"
(fillarray s ?-)
     ⇒ "------------------"

arrayが文字列でobjectが文字でなければ、結果はwrong-type-argumentエラーとなる。

配列と判っているオブジェクトにたいしては、一般的なシーケンス関数copy-sequencelengthが有用なときがよくあります。シーケンスを参照してください。


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

6.4 ベクター

ベクター(vector)とは任意のLispオブジェクトを要素にもつことができる、一般用途のための配列です(対照的に文字列の要素は文字のみ。文字列と文字を参照)。Emacsではベクターはキーシーケンス(キーシーケンスを参照)、シンボル検索用のテーブル(シンボルの作成とinternを参照)、バイトコンパイルされた関数表現の一部(バイトコンパイルを参照)などの多くの目的で使用されます。

他の配列と同様、ベクターは0基準のインデックスづけを使用し、1番目の要素はインデックス0になります。

ベクターは角カッコ(square brackets)で囲まれた要素としてプリントされます。したがってシンボルabaを要素にもつベクターは、[a b a]とプリントされます。Lisp入力として同じ方法でベクターを記述できます。

文字列や数値と同様にベクターは定数として評価され、評価された結果は同じベクターになります。ベクターの要素は評価も確認もされません。自己評価を行うフォームを参照してください。角カッコ(square brackets)で記述されたベクターをasetや他の破壊的操作を通じて修正しないでください。可変性を参照してください。

以下はこれらの原理を表す例です:

(setq avector [1 two '(three) "four" [five]])
     ⇒ [1 two '(three) "four" [five]]
(eval avector)
     ⇒ [1 two '(three) "four" [five]]
(eq avector (eval avector))
     ⇒ t

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

6.5 ベクターのための関数

ベクターに関連した関数をいくつか示します:

Function: vectorp object

この関数はobjectがベクターならtをリターンする。

(vectorp [a])
     ⇒ t
(vectorp "asdf")
     ⇒ nil
Function: vector &rest objects

この関数は引数objectsを要素にもつベクターを作成してリターンする。

(vector 'foo 23 [bar baz] "rats")
     ⇒ [foo 23 [bar baz] "rats"]
(vector)
     ⇒ []
Function: make-vector length object

この関数は各要素がobjectに初期化された、length個の要素からなる新しいベクターをリターンする。

(setq sleepy (make-vector 9 'Z))
     ⇒ [Z Z Z Z Z Z Z Z Z]
Function: vconcat &rest sequences

この関数はsequencesのすべての要素を含む新しいベクターをリターンする。引数sequencesは正リスト、ベクター、文字列、ブールベクター。sequencesが与えられければ空のベクターがリターンされる。

値は空のベクター、またはすべての既存ベクターとeqではないような空ではない新しいベクターのいずれか。

(setq a (vconcat '(A B C) '(D E F)))
     ⇒ [A B C D E F]
(eq a (vconcat a))
     ⇒ nil
(vconcat)
     ⇒ []
(vconcat [A B C] "aa" '(foo (6 7)))
     ⇒ [A B C 97 97 foo (6 7)]

vconcat関数は、引数としてバイトコード関数オブジェクトも受け取ることができる。これはバイトコード関数オブジェクトの内容全体にアクセスするのを容易にするための特別な機能である。バイトコード関数オブジェクトを参照のこと。

結合を行なう他の関数については関数のマッピングmapconcat文字列の作成concatコンスセルおよびリストの構築appendを参照されたい。

append関数はベクターを同じ要素をもつリストに変換する方法も提供します:

(setq avector [1 two (quote (three)) "four" [five]])
     ⇒ [1 two '(three) "four" [five]]
(append avector nil)
     ⇒ (1 two '(three) "four" [five])

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

6.6 文字テーブル

文字テーブル(char-table)はベクターとよく似ていますが、文字テーブルは文字コードによりインデックスづけされます。文字テーブルのインデックスには、修飾キーをともなわない任意の有効な文字コードを使用できます。他の配列と同様に、arefasetで文字テーブルの要素にアクセスできます。加えて、文字テーブルは追加のデータを保持するために、特定の文字コードに関連づけられていないエキストラスロット(extra slots)をもつことができます。ベクターと同様、文字テーブルは定数として評価され、任意の型の要素を保持できます。

文字テーブルはそれぞれサブタイプ(subtype)をもち、これは2つの目的をもつシンボルです:

文字テーブルは親(parent)をもつことができ、これは他の文字テーブルです。文字テーブルが親をもつ場合、その文字テーブルで特定の文字cにたいしてnilが指定されていたら、親と指定された文字テーブルで指定された値を継承します。言い方を変えると、文字テーブルchar-tablecnilが指定されていたら、(aref char-table c)char-tableの親の値をリターンします。

文字テーブルはデフォルト値(default value)をもつこともできます。デフォルト値をもつとき、文字テーブルchar-tablecにたいしてnil値を指定すると、(aref char-table c)はデフォルト値をリターンします。

Function: make-char-table subtype &optional init

サブタイプsubtype(シンボル)をもつ、新たに作成された文字テーブルをリターンする。各要素はinitに初期化され、デフォルトはnil。文字テーブルが作成された後で、文字テーブルのサブタイプを変更することはできない。

すべての文字テーブルは、インデックスとなる任意の有効な文字テーブルのための空間をもつので、文字テーブルの長さを指定する引数はない。

subtypeがシンボルプロパティーchar-table-extra-slotsをもつなら、それはその文字列テーブル内のエキストラスロットの数を指定する。値には0から10の整数を指定し、これ以外ならmake-char-tableはエラーとなる。subtypeがシンボルプロパティーchar-table-extra-slots(プロパティリストを参照)をもたなければ、その文字テーブルはエキストラスロットをもたない。

Function: char-table-p object

この関数はobjectが文字テーブルならt、それ以外はnilをリターンする。

Function: char-table-subtype char-table

この関数はchar-tableのサブタイプのシンボルをリターンする。

文字テーブルのデフォルト値にアクセスするための特別な関数は存在しません。これを行なうにはchar-table-rangeを使用します(以下参照)。

Function: char-table-parent char-table

この関数はchar-tableの親をリターンする。親は常にnilか他の文字テーブルである。

Function: set-char-table-parent char-table new-parent

この関数はchar-tableの親をnew-parentにセットする。

Function: char-table-extra-slot char-table n

この関数はchar-tableのエキストラスロットn (0基準)の内容をリターンする。文字テーブルのエキストラスロットの数は文字テーブルのサブタイプにより決定される。

Function: set-char-table-extra-slot char-table n value

この関数はchar-tableのエキストラスロットn (0基準)にvalueを格納する。

文字テーブルは1つの文字コードにたいして1つの要素値(element value)を指定できます。文字テーブルは文字セット全体にたいして値を指定することもできます。

Function: char-table-range char-table range

この関数は文字範囲rangeにたいしてchar-tableで指定された値をリターンする。可能なrangeは以下のとおり:

nil

デフォルト値への参照。

char

文字charにたいする要素への参照(charは有効な文字コードであると仮定)。

(from . to)

包括的な範囲‘[from..to]’内のすべての文字を参照するコンスセル。

Function: set-char-table-range char-table range value

この関数はchar-table内の文字範囲rangeにたいして値をセットする。可能なrangeは以下のとおり:

nil

デフォルト値への参照。

t

文字コード範囲の全体を参照。

char

文字charにたいする要素への参照(charは有効な文字コードであると仮定)。

(from . to)

包括的な範囲‘[from..to]’内のすべての文字を参照するコンスセル。

Function: map-char-table function char-table

この関数はchar-tableの非nil値ではない各要素にたいして引数functionを呼び出す。functionの呼び出しでは2つの引数(keyとvalue)が指定される。keyはchar-table-rangeにたいする可能なrange (有効な文字か、同じ値を共有する文字範囲を指定するコンスセル(from . to))。valueは(char-table-range char-table key)がリターンする値。

全体として、functionに渡されるkey-valueのペアはchar-tableに格納されたすべての値を表す。

リターン値は常にnilである。map-char-table呼び出しを有用にするためにfunctionは副作用をもつこと。たとえば以下は構文テーブルを調べる方法:

(let (accumulator)
   (map-char-table
    (lambda (key value)
      (setq accumulator
            (cons (list
                   (if (consp key)
                       (list (car key) (cdr key))
                     key)
                   value)
                  accumulator)))
    (syntax-table))
   accumulator)
⇒
(((2597602 4194303) (2)) ((2597523 2597601) (3))
 ... (65379 (5 . 65378)) (65378 (4 . 65379)) (65377 (1))
 ... (12 (0)) (11 (3)) (10 (12)) (9 (0)) ((0 8) (3)))

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

6.7 ブールベクター

ブールベクター(bool-vector)はベクターとよく似ていますが、値にtnilしか格納できません。ブールベクターの要素に非nil値の格納を試みたると、そこにはtが格納されます。すべての配列と同様、ブールベクターのインデックスは0から開始され、一度ブールベクターが作成されたら長さを変更することはできません。ブールベクターは定数として評価されます。

ブールベクターを処理する特別な関数がいくつかあります。その関数以外にも、他の種類の配列に使用されるのと同じ関数でブールベクターを操作できます。

Function: make-bool-vector length initial

initialに初期化されたlength要素の新しいブールベクターをリターンする。

Function: bool-vector &rest objects

この関数は引数objectsを要素にもつブールベクターを作成してリターンする。

Function: bool-vector-p object

この関数はobjectがブールベクターであればt、それ以外はnilをリターンする。

以下で説明するように、ブールベクターのセット処理を行なう関数がいくつかあります:

Function: bool-vector-exclusive-or a b &optional c

ブールベクターabビットごとの排他的論理和(bitwise exclusive or)をリターンする。オプション引数cが与えられたら、この処理の結果はcに格納される。引数にはすべて同じ長さのブールベクターを指定すること。

Function: bool-vector-union a b &optional c

ブールベクターabビットごとの論理和(bitwise or)をリターンする。オプション引数cが与えられたら、この処理の結果はcに格納される。引数にはすべて同じ長さのブールベクターを指定すること。

Function: bool-vector-intersection a b &optional c

ブールベクターabビットごとの論理積(bitwise and)をリターンする。オプション引数cが与えられたら、この処理の結果はcに格納される。引数にはすべて同じ長さのブールベクターを指定すること。

Function: bool-vector-set-difference a b &optional c

ブールベクターab差集合(set difference)をリターンする。オプション引数cが与えられたら、この処理の結果はcに格納される。引数にはすべて同じ長さのブールベクターを指定すること。

Function: bool-vector-not a &optional b

ブールベクターa補集合(set complement)をリターンする。オプション引数bが与えられたら、この処理の結果はbに格納される。引数にはすべて同じ長さのブールベクターを指定すること。

Function: bool-vector-subsetp a b

a内のすべてのt値がbでもt値ならt、それ以外はnilをリターンする。引数にはすべて同じ長さのブールベクターを指定すること。

Function: bool-vector-count-consecutive a b i

iから始まるaの、bと等しい連続する要素の数をリターンする。aはブールベクターで、btniliaのインデックス。

Function: bool-vector-count-population a

ブールベクターaからtであるような要素の数をリターンする。

長さ8以下のブール値のプリント表記は1文字で表されます。

(bool-vector t nil t nil)
     ⇒ #&4"^E"
(bool-vector)
     ⇒ #&0""

他のベクター同様、vconcatを使用してブールベクターをプリントできます:

(vconcat (bool-vector nil t nil t))
     ⇒ [nil t nil t]

以下はブールベクターを作成、確認、更新する別の例です:

(setq bv (make-bool-vector 5 t))
     ⇒ #&5"^_"
(aref bv 1)
     ⇒ t
(aset bv 3 nil)
     ⇒ nil
bv
     ⇒ #&5"^W"

control-_の2進コードは11111、control-Wは10111なので、この結果は理にかなっています。


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

6.8 オブジェクト用固定長リングの管理

リング(ring)は挿入、削除、ローテーション、剰余(modulo)でインデックスづけされた、参照と走査(traversal)をサポートする固定長のデータ構造です。ringパッケージにより効率的なリングデータ構造が実装されています。このパッケージは、このセクションにリストした関数を提供します。

Emacsにあるkillリングやマークリングのようないくつかのリングは、実際には単なるリストとして実装されていることに注意してください。したがってこれらのリングにたいしては、以下の関数は機能しないでしょう。

Function: make-ring size

この関数はsizeオブジェクトを保持できる、新しいリングをリターンする。sizeは整数。

Function: ring-p object

この関数はobjectがリングならt、それ以外はnilをリターンする。

Function: ring-size ring

この関数はringの最大の要素数をリターンする。

Function: ring-length ring

この関数はringに現在含まれるオブジェクトの数をリターンする。値がring-sizeのリターンする値を超えることはない。

Function: ring-elements ring

この関数はring内のオブジェクトのリストをリターンする。リストの順序は新しいオブジェクトが先頭になる。

Function: ring-copy ring

この関数は新しいリングとしてringのコピーをリターンする。新しいリングはringと同じ(eqな)オブジェクトを含む。

Function: ring-empty-p ring

この関数はringが空ならt、それ以外はnilをリターンする。

リング内の1番新しい要素は常にインデックス0をもちます。より大きいインデックスは、より古い要素に対応します。インデックスはリング長のmoduloにより計算されます。インデックス-1は1番古い要素、-2は次に古い要素、...となります。

Function: ring-ref ring index

この関数はインデックスindexにあるring内のオブジェクトをリターンする。indexには負やリング長より大きい数を指定できる。ringが空ならring-refはエラーをシグナルする。

Function: ring-insert ring object

この関数は1番新しい要素としてobjectringに挿入してobjectをリターンする。

リングが満杯なら新しい要素用の空きを作るために、挿入により1番古い要素が削除される。

Function: ring-remove ring &optional index

ringからオブジェクトを削除してそのオブジェクトをリターンする。引数indexはどのアイテムを削除するかを指定する。これがnilなら、それは1番古いアイテムを削除することを意味する。ringが空ならring-removeはエラーをシグナルする。

Function: ring-insert-at-beginning ring object

この関数は1番古い要素としてobjectringに挿入する。リターン値に意味はない。

リングが満杯なら、この関数は挿入される要素のための空きを作るために1番新しい要素を削除する。

Function: ring-resize ring size

ringのサイズをsizeにセットする。新たなサイズのほうが小さければリング内の古いアイテムは破棄される。

リングサイズを超過しないよう注意すれば、そのリングをFIFO(first-in-first-out: 先入れ先出し)のキューとして使用することができます。たとえば:

(let ((fifo (make-ring 5)))
  (mapc (lambda (obj) (ring-insert fifo obj))
        '(0 one "two"))
  (list (ring-remove fifo) t
        (ring-remove fifo) t
        (ring-remove fifo)))
     ⇒ (0 t one t "two")

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

7 レコード

レコードの目的はEmacsにビルトインされていない新たな型のオブジェクトをプログラマーが作成できるようにすることです。これらはcl-defstructdefclassのインスタンスを表現する基礎として使用されています。

レコードオブジェクトは内部的にはベクターと似ています。レコードオブジェクトのスロットはarefを使用してアクセス可能であり、copy-sequenceを使用してコピーできます。しかし最初のスロットはtype-ofがリターンする型を保持するために使用されます。更に現実装ではレコードは最大で4096スロットを所有できますが、ベクターはそれより多くのスロットを所有できます。レコードは配列と同じように0基準のインデックスを使用するので、最初のスロットはインデックスが0になります。

型スロット(type slot)はシンボルか型記述子であるべきです。型記述子なら型を命名するシンボルがリターンされます。型記述子を参照してください。その他の種類のオブジェクトはすべてそのままリターンされます。

レコードのプリント表現では‘#s’の後にコンテンツを指定するリストが続きます。リストの最初の要素はそのレコードの型である必要があります。後続の要素はレコードのスロットです。

レコードの型を新たに定義するLispプログラムは他の型名との衝突を避けるために、通常はレコード型を導入する部分では型名にパッケージの命名規約を使用するべきです。衝突する可能性がある型名は、パッケージが定義したレコード型のロード時には不明かもしれないことに注意してください。これらは将来のある時点でロードされる可能性があります。

レコードは評価にたいして定数とみなされます。評価すると結果は同じレコードになります。レコードは評価されずにスロットのチェックさえ行われません。自己評価を行うフォームを参照してください。


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

7.1 レコード関数

Function: recordp object

この関数はobjectがレコードならtをリターンする。

(recordp #s(a))
     ⇒ t
Function: record type &rest objects

この関数は型がtypeであり、残りのスロットが残りの引数objectsであるようなレコードを作成してリターンする。

(record 'foo 23 [bar baz] "rats")
     ⇒ #s(foo 23 [bar baz] "rats")
Function: make-record type length object

この関数は型がtypeobjectで初期化されたスロット数がlengthの新たなレコードをリターンする。

(setq sleepy (make-record 'foo 9 'Z))
     ⇒ #s(foo Z Z Z Z Z Z Z Z Z)

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

7.2 後方互換

レコードを使用しない古いバージョンのcl-defstructでコンパイルされたコードを新しいEmacsで実行したときに問題が発生するかもしれません。この魔問題を軽減するために、Emacsは古いcl-defstructの使用を検知した際に古い構造体オブジェクトがレコードであるかのように処理するモードを有効にします。

Function: cl-old-struct-compat-mode arg

argが正なら旧スタイルの構造体にたいする後方互換を有効にする。


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

8 ハッシュテーブル

ハッシュテーブル(hash table)は非常に高速なルックアップテーブルの一種で、キーに対応する値をマップするという点ではalist(連想リストを参照)に似ています。ハッシュテーブルは以下の点でalistと異なります:

Emacs Lispは一般的な用途のハッシュテーブルデータ型とともに、それらを処理する一連の関数を提供します。ハッシュテーブルは‘#s’、その後にハッシュテーブルのプロパティーと内容を指定するリストが続く、特別なプリント表現をもちます。ハッシュテーブルの作成を参照してください(ハッシュ表記の最初に使用される‘#’文字は、読み取り表現をもたないオブジェクトのプリント表現であり、これはハッシュテーブルに何も行わない。プリント表現と読み取り構文を参照のこと)。

obarray(オブジェクト配列)もハッシュテーブルの一種ですが、これらは異なる型のオブジェクトであり、intern(インターン)されたシンボルを記録するためだけに使用されます(シンボルの作成とinternを参照)。


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

8.1 ハッシュテーブルの作成

ハッシュテーブルを作成する基本的な関数はmake-hash-tableです。

Function: make-hash-table &rest keyword-args

この関数は指定された引数に対応する新しいハッシュテーブルを作成する。引数はキーワード(特別に認識される独自のシンボル)と、それに対応する値を交互に指定することで構成される。

make-hash-tableではいくつかのキーワードが意味をもつが、実際に知る必要があるのは:test:weaknessの2つだけである。

:test test

これはそのハッシュテーブルにたいしてキーを照合する方法を指定する。デフォルトはeqlであり他の代替としてはeqequalがある:

eql

キーが数字ならそれらがequal、つまりそれらの値が等しくどちらも整数か浮動少数点数なら同一。それ以外なら別の2つのオブジェクトは決して同一とならない。

eq

別の2つのLispオブジェクトはすべて別のキーになる。

equal

別の2つのLispオブジェクトで、それらがequalなら同一のキーである。

testにたいして追加の選択肢を定義するために、define-hash-table-test (ハッシュの比較の定義を参照)を使用することができる。

:weakness weak

ハッシュテーブルのweakness(強度)は、ハッシュテーブル内に存在するキーと値をガーベージコレクションから保護するかどうかを指定する。

weakにはnilkeyvaluekey-or-valuekey-and-value、またはt(key-and-valueのエイリアス)のいずれかを指定しなければならない。weakkeyならそのハッシュテーブルは、(キーが他の場所で参照されていなければ)ハッシュテーブルのキーがガーベージコレクトされるのを妨げられない。ある特定のキーがガーベージコレクトされると、それに対応する連想はハッシュテーブルから削除される。

weakvalueならそのハッシュテーブルは、(値が他の場所で参照されていなければ)ハッシュテーブルの値がガベージコレクトされるのを妨げませんられない。ある特定の値がガーベージコレクトされると、それに対応する連想はハッシュテーブルから削除される。

weakkey-and-value(かt)なら、その連想を保護するためにはキーと値の両方が生きていなければならない。したがってそのハッシュテーブルは、キーと値の一方だけをガーベージコレクトから守ることはしない。キーか値のどちらか一方がガーベージコレクトされたら、その連想は削除される。

weakkey-or-valuenara、キーか値のどちらか一方で、その連想を保護することができる。したがってキーと値の両方がガベージコレクトされたときだけ(それがハッシュテーブル自体にたいする参照でなければ)、ハッシュテーブルからその連想が削除される。

weakのデフォルトはnilなので、ハッシュテーブルから参照されているキーと値はすべてガーベージコレクションから保護される。

:size size

これはそのハッシュテーブルに保管しようとしている、連想の数にたいするヒントを指定する。数が概算で判っていれば、この方法でそれを指定して処理を若干効率的にすることができる。小さすぎるサイズを指定すると、そのハッシュテーブルは必要に応じて自動的に拡張されるが、これを行なうために時間が余計にかかる。

デフォルトのサイズは65。

:rehash-size rehash-size

ハッシュテーブルに連想を追加するとき、そのテーブルが満杯ならテーブルを自動的に拡張する。この値はその際にどれだけハッシュテーブルを拡張するかを指定する。

rehash-sizeが整数(正であること)なら、通常のサイズにrehash-sizeに近い値を加えることによりハッシュテーブルが拡張される。rehash-sizeが浮動小数(1より大きい方がよい)なら、古いサイズにその数に近い値を乗じることによりハッシュテーブルが拡張される。

デフォルト値は1.5。

:rehash-threshold threshold

これはハッシュテーブルが一杯(なのでもっと大きく拡張する必要がある)だと判断される基準を指定する。thresholdの値は1以下の正の浮動小数点数であること。実際のエントリー数が通常のサイズにたいする指定した割合に近い値を超えるとハッシュテーブルは一杯(full)になる。thresholdのデフォルトは0.8125。

ハッシュテーブルのプリント表現を使用して、新しいハッシュテーブルを作成することもできます。指定されたハッシュテーブル内の各要素が、有効な入力構文(プリント表現と読み取り構文を参照)をもっていれば、Lispリーダーはこのプリント表現を読み取ることができます。たとえば以下は値val1(シンボル)と300(数字)に関連づけられた、キーkey1key2(両方ともシンボル)を、新しいハッシュテーブルに指定します。

#s(hash-table size 30 data (key1 val1 key2 300))

ハッシュテーブルのプリント表現は‘#s’と、その後の‘hash-table’で始まるリストにより構成されます。このリストの残りの部分はそのハッシュテーブルのプロパティーと初期内容を指定する、0個以上のプロパティーと値からなるペアで構成されるべきです。プロパティーと値はそのまま読み取られます。有効なプロパティー名はsizetestweaknessrehash-sizerehash-thresholddataです。dataプロパティーは、初期内容にたいするキーと値のペアからなるリストであるべきです。他のプロパティーは、上記で説明したmake-hash-tableのキーワード(:size:testなど)と同じ意味をもちます。

バッファーやフレームのような、入力構文をもたないオブジェクトを含んだ初期内容をもつハッシュテーブルを指定できないことに注意してください。そのようなオブジェクトは、ハッシュテーブルを作成した後に追加します。


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

8.2 ハッシュテーブルへのアクセス

このセクションではハッシュテーブルにアクセスしたり、連想を保管する関数を説明します。比較方法による制限がない限り、一般的には任意のLispオブジェクトをハッシュキーとして使用できます。

Function: gethash key table &optional default

この関数はtablekeyを照合してそれに関連づけられたvaluetable内にkeyをもつ連想が存在しなければdefaultをリターンする。

Function: puthash key value table

この関数はtable内に値valueをもつkeyの連想を挿入します。tableがすでにkeyの連想をもつなら、valueで古い連想値を置き換える。

Function: remhash key table

この関数はtablekeyの連想があればそれを削除する。keyが連想をもたなければremhashは何も行なわない。

Common Lispに関する注意: Common Lispではremhashが実際に連想を削除したときは非nil、それ以外はnilをリターンする。Emacs Lispではremhashは常にnilをリターンする。

Function: clrhash table

この関数はハッシュテーブルtableからすべての連想を削除するので、そのハッシュテーブルは空になる。これはハッシュテーブルのクリーニング(clearing)とも呼ばれる。

Common Lispに関する注意: Common Lispではclrhashは空のtableをリターンする。Emacs Lispではnilをリターンする。

Function: maphash function table

この関数はtable内の各連想にたいして一度ずつfunctionを呼び出す。関数functionは2つの引数 — tableにリストされたkeyと、それに関連づけられたvalue — を受け取ること。maphashnilをリターンする。


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

8.3 ハッシュの比較の定義

define-hash-table-testでキーを照合する新しい方法を定義できます。この機能を使用するにはハッシュテーブルの動作方法と、ハッシュコード(hash code)の意味を理解する必要があります。

概念的にはハッシュテーブルを1つの連想を保持できるスロットがたくさんある巨大な配列として考えることができます。キーを照合するにはまず、gethashがキーから整数のハッシュコードを計算します。配列の長さをmoduloとしてこの整数を減らして、配列内のインデックスを生成することができます。それからキーが見つかったかどうか確認するためにそのスロット、もし必要なら近くのスロットを探します。

しあがってキーを照合する新たな方法を定義するにはキーからハッシュコードを計算する関数、および2つのキーを直接比較する関数の両方を指定する必要があります。この2つの関数は互いに一貫性をもつ必要があります。すなわちキーを比較してequalなら、2つのキーのハッシュコードは同一であるべきです。さらに(ガーベージコレクターからの呼び出しのように)2つの関数は任意のタイミングで呼び出される可能性があるので、関数が副作用をもたないこと、すぐにリターンすること、そしてこれらの関数の挙動はそのキーの不変の性質だけに依存する必要があります。

Function: define-hash-table-test name test-fn hash-fn

この関数はnameという名前の新たなハッシュテーブルテストを定義します。

この方法でnameを定義した後は、make-hash-tableの引数testにこれを使用することができる。これを行なう際は、そのハッシュテーブルのキー値の比較にtest-fn、キー値からハッシュコードを計算するためにhash-fnを使用することになる。

関数test-fnは2つの引数(2つのキー)をとり、それらが同一と判断されたときは非nilをリターンする。

関数hash-fnは1つの引数(キー)を受け取り、そのキーのハッシュコード(整数)をリターンすること。よい結果を得るために、その関数は負のfixnumを含むfixnumの全範囲をハッシュコードに使用すること。

指定された関数は、プロパティーhash-table-testの配下の、nameというプロパティーリストに格納される。そのプロパティーの値形式は(test-fn hash-fn)

Function: sxhash-equal obj

この関数はLispオブジェクトobjのハッシュコードをリターンする。リターン値はobjと、それが指す別のLispオブジェクトの内容を表す整数。

2つのオブジェクトobj1obj2が等しければ(sxhash-equal obj1)(sxhash-equal obj2)は同じ整数になる。

2つのオブジェクトがequalでなければ通常はsxhash-equalがreturnする値は異なるが、常に異なるとは限らない。稀(運次第)にsxhash-equalが同じ結果を与える、2つの異なって見えるオブジェクトに遭遇するかもしれない。

Common Lispに関する注意: Common Lispではこれに似た関数はsxhashと呼ばれる。Emacsは互換性のためにsxhash-equalにたいするエイリアスとしてこの名前を提供している。

Function: sxhash-eq obj

この関数はLispオブジェクトobjにたいするハッシュコードをリターンする。結果はobjの識別値でありコンテンツではない。

2つのオブジェクトobj1obj2eqなら(sxhash-eq obj1)(sxhash-eq obj2)は同じ整数。

Function: sxhash-eql obj

この関数はeqlによる比較に適したLispオブジェクトobjにたいするハッシュコードをリターンする。つまり浮動小数点数とbignum以外のobjなら、それにたいする識別値(浮動小数点数ならその値にたいするハッシュコード)を生成する。

2つのオブジェクトobj1obj2eqlなら(sxhash-eql obj1)(sxhash-eql obj2)は同じ整数。

以下はlcaseを区別しない文字列のキーをもつハッシュテーブルを作成する例です。

(defun case-fold-string= (a b)
  (eq t (compare-strings a nil nil b nil nil t)))
(defun case-fold-string-hash (a)
  (sxhash-equal (upcase a)))

(define-hash-table-test 'case-fold
  'case-fold-string= 'case-fold-string-hash)

(make-hash-table :test 'case-fold)

以下は事前に定義されたテスト値equalと等価なテストを行なうハッシュテーブルを定義できるという例です。キーは任意のLispオブジェクトで、equalに見えるオブジェクトは同じキーと判断されます。

(define-hash-table-test 'contents-hash 'equal 'sxhash-equal)

(make-hash-table :test 'contents-hash)

ハッシュ関数の実装はセッション中に変更されたり、アークテクチャーごとに異なるかもしれなオブジェクトストレージのいくつかの詳細を使用するので、LispプログラムはEmacsセッションの間はハッシュコードが保存されることに依存するべきではありません


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

8.4 ハッシュテーブルのためのその他関数

以下はハッシュテーブルに作用する他の関数です。

Function: hash-table-p table

この関数はtableがハッシュテーブルオブジェクトなら非nilをリターンする。

Function: copy-hash-table table

この関数はtableのコピーを作成してリターンする。そのテーブル自体がコピーされたものである場合のみ、キーと値が共有される。

Function: hash-table-count table

この関数はtable内の実際のエントリー数をリターンする。

Function: hash-table-test table

この関数はハッシュを行なう方法と、キーを比較する方法を指定するために、table作成時に与えられたtestの値をリターンする。ハッシュテーブルの作成make-hash-tableを参照されたい。

Function: hash-table-weakness table

この関数はハッシュテーブルtableに指定されたweakの値をリターンする。

Function: hash-table-rehash-size table

この関数はtableのrehash-sizeをリターンする。

Function: hash-table-rehash-threshold table

この関数はtableのrehash-thresholdをリターンする。

Function: hash-table-size table

この関数はtableの現在の定義されたサイズをリターンする。


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

9 シンボル

シンボル(symbol)は一意な名前をもつオブジェクトです。このチャプターではシンボル、シンボルの構成要素とプロパティーリスト、およびシンボルの作成とインターンする方法を説明します。別のチャプターではシンボルを変数として使用したり、関数名として使用する方法が説明されています。変数関数を参照してください。シンボルの正確な入力構文については、シンボル型を参照してください。

symbolpを使用して、任意のLispオブジェクトがシンボルかどうかをテストできます:

Function: symbolp object

この関数はobjectがシンボルならt、それ以外はnilをリターンする。


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

9.1 シンボルの構成要素

各シンボルは4つの構成要素(もしくは“セル”)をもち、構成要素はそれぞれ別のオブジェクトを参照します:

プリント名(print name)

そのシンボルの名前。

値(value)

変数としてのそのシンボルの現在値。

関数(function)

そのシンボルの関数定義。シンボル、キーマップ、キーボードマクロも保持できる。

プロパティーリスト(property list)

そのシンボルのプロパティーリスト。

プリント名のセルは常に文字列を保持し、それを変更することはできません。他の3つのセルには、任意のLispオブジェクトをセットすることができます。

プリント名のセルはシンボルの名前となる文字列を保持します。シンボルはシンボル名によりテキストとして表されるので、2つのシンボルが同じ名前をもたないことが重要です。Lispリーダーはシンボルを読み取るごとに、それを新規作成する前に、指定されたシンボルがすでに存在するかを調べます。シンボルの名前を得るには関数symbol-name(シンボルの作成とinternを参照)を使用します。

値セルは変数としてのシンボルの値(そのシンボル自身がLisp式として評価されたときに得る値)を保持します。ローカルバインディング(local binding)スコーピングルール(scoping rules)等のような複雑なものを含めて、変数のセットや取得方法については変数を参照してください。ほとんどのシンボルは値として任意のLispオブジェクトをもつことができますが、一部の特別なシンボルは変更できない値をもちます。これらにはnilt、および名前が‘:’で始まるすべてのシンボル(キーワード(keyword)と呼ばれる)が含まれます。変更不可な変数を参照してください。

関数セルはシンボルの関数定義を保持します。実際はにはfooの関数セルの中に保管されている関数を意味するときに、“関数foo”といってそれを参照することがよくあります。わたしたちは必要なときだけ、これを明確に区別することにします。関数セルは通常は関数(関数を参照)か、マクロ(マクロを参照)を保持するために使用されます。しかし関数セルはシンボル(シンボル関数インダイレクションを参照)、キーボードマクロ(キーボードマクロを参照)、キーマップ(キーマップを参照)、またはオートロードオブジェクト(自動ロードを参照)を保持するためにも使用できます。シンボルの関数セルの内容を得るには、関数symbol-function (関数セルの内容へのアクセスを参照)を使用します。

プロパティーリストのセルは、通常は正しくフォーマットされたプロパティーリストを保持するべきです。シンボルのプロパティーリストを得るには関数symbol-plistを使用します。シンボルのプロパティを参照してください。

マクロセルと値セルがvoid(空)のときもあります。voidとはそのセルがどのオブジェクトも参照していないことを意味します(これはシンボルvoidを保持するのともシンボルnilを保持するのとも異なる)。voidの関数セルまたは値セルを調べようとすると結果は‘Symbol's value as variable is void’のようなエラーとなります。

各シンボルは値セルと関数セルを別個にもつので、変数名と関数名が衝突することはありません。たとえばシンボルbuffer-file-nameが値(カレントバッファーでvisitされているファイルの名前)をもつと同様に、関数定義(ファイルの名前をリターンするプリミティブ関数)をもつことができます:

buffer-file-name
     ⇒ "/gnu/elisp/symbols-ja.texi"
(symbol-function 'buffer-file-name)
     ⇒ #<subr buffer-file-name>

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

9.2 シンボルの定義

定義(definition)とは、特別な方法での使用の意図を宣言する特別な種類のLisp式です。定義とは通常はシンボルにたいする値を指定するか、シンボルにたいする1つの種類の使用についての意味とその方法で使用する際のシンボルの意味のドキュメントを指定します。したがってシンボルを変数として定義すると、その変数の初期値に加えてその変数のドキュメントを提供できます。

defvardefconstグローバル変数(global variable) — Lispプログラムの任意の箇所からアクセスできる変数 — として定義するためのスペシャルフォームです。変数についての詳細は変数を参照してください。カスタマイズ可能な変数を定義するにはdefcustom (サブルーチンとしてdefvarも呼び出す)を使用します(カスタマイゼーション設定を参照)。

最初にシンボルが変数として定義されているかどうかに関わらず、原則としてsetqで任意のシンボルに値を割り当てることができます。しかし使用したいグローバル変数それぞれにたいして変数定義を記述するべきです。さもないとレキシカルスコープ(変数のバインディングのスコーピングルールを参照)が有効なときに変数が評価されると、Lispプログラムが正しく動作しないかもしれません。

defunはラムダ式(lambda expression)を生成して、そのシンボルの関数セルに格納することにより、そのシンボルを関数として定義します。したがってこのシンボルの関数定義は、そのラムダ式になります(関数セルの内容を意味する用語“関数定義(function definition)”は、defunがシンボルに関数としての定義を与えるというアイデアに由来する)。関数を参照してください。

defmacroはシンボルをマクロとして定義します。これはマクロオブジェクトを作成してシンボルの関数セルにそれを格納します。シンボルにはマクロと関数を与えることができますが、マクロと関数定義はどちらも関数セルに保持されるのにたいし、関数セルに保持できるのは常にただ1つのLispオブジェクトなので、一度に両方を行なうことはできないことに注意してください。マクロを参照してください。

前に注記したようにEmacs Lispではシンボルを(たとえばdefvarで)変数として定義して、同じシンボルを(たとえばdefunで)関数やマクロとして両方定義することができます。このような定義は衝突しません。

これらの定義は、プログラミングツールのガイドを果たすこともできます。たとえば、C-h fおよびC-h vコマンドは、関係ある変数、関数、マクロ定義へのリンクを含むヘルプバッファーを作成します。Name Help in The GNU Emacs Manualを参照してください。


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

9.3 シンボルの作成とintern

GNU Emacs Lispでシンボルが作成される方法を理解するには、Lispがシンボルを読み取る方法を理解しなければなりません。Lispは、同じ文字綴りを読み取ったら、毎回同じシンボルを見つけることを保証しなければなりません。これに失敗すると、完全な混乱を招くでしょう。

Lispリーダーがシンボルに出会うと、Lispリーダーは名前のすべての文字を読み取ります。その後Lispリーダーはobarray(オブジェクト配列)と呼ばれるテーブル内のインデックスを決めるために、これらの文字をハッシュ(hash)します。ハッシュ化(hashing)は何かを照合するのに効果的な方法です。たとえばJan Jonesを見つけるときは、電話帳を表紙から1頁ずつ探すのではなくJの頁から探し始めます。これはハッシュ化の簡単なバージョンです。obarrayの各要素は与えられたハッシュコードとともに、すべてのシンボルを保持するバケット(bucket)です。与えられた名前を探すためには、バケットの中からハッシュコードがその名前であるような、すべてのシンボルを探すのが効果的です(同じアイデアは一般的なEmacsのハッシュテーブルでも使用されていがこれらはデータ型が異なる。ハッシュテーブルを参照されたい)。

探している名前のシンボルが見つかったら、リーダーはそのシンボルを使用します。obarrayにその名前のシンボルが含まれなければ、リーダーは新しいシンボルを作成してそれをobarrayに追加します。特定の名前のシンボルを探して追加することをインターン(intern)と言い、これが行なわれた後はそのシンボルはインターンされたシンボル(interned symbol)と呼ばれます。

インターンすることによりある特定の名前のシンボルは、各obarrayに1つだけであることが保証されます。同じ名前のシンボルが他に存在するかもしれませんが、同じobarrayには存在しません。したがってリーダーは、(同じobarrayを読みつづける限り)同じ名前にたいして同じシンボルを取得します。

インターンは通常はリーダー内で自動的に発生しますが、他のプログラムがこれを行なう必要がある場合もあります。たとえばM-xコマンドはその後にミニバッファーを使用してコマンド名を文字列として取得して、その文字列をインターンしてからインターンされたその名前のシンボルを得ます。

すべてのシンボルを含むobarrayはありません。実際にどのobarrayにも含まれないシンボルがいくつかあります。これらはインターンされていないシンボル(uninterned symbols)と呼ばれます。インターンされていないシンボルも、他のシンボルと同じく4つのセルをもちます。しかしインターンされていないシンボルへのアクセスを得る唯一の方法は、他の何らかのオブジェクトとして探すか、変数の値として探す方法だけです。

インターンされていないシンボルの作成は、Lispコードを生成するとき有用です。なぜなら作成されたコード内で変数として使用されているインターンされていないシンボルは、他のLispプログラムで使用されている任意の変数と競合することはありえないからです。

Emacs Lispではobarrayはベクターです。ベクター内の各要素がバケットになります。要素の値は、名前がそのバケットにハッシュされるようなインターンされたシンボル、またはバケットが空のときは0です。インターンされたシンボルは、そのバケット内の次のシンボルへの内部リンク(ユーザーからは見えない)をもちます。これらのリンクは不可視なので、mapatoms (以下参照)を使用する方法をのぞき、obarray内のすべてのシンボルを探す方法はありません。バケット内のシンボルの順番に意味はありません。

空のobarrayではすべての要素が0なので、(make-vector length 0)でobarrayを作成することができます。obarrayを作成する有効な方法はこれだけです。長さに素数を指定するとよいハッシュ化がされる傾向があります。2の累乗から1減じた長さもよい結果を生む傾向があります。

自分でobarrayにシンボルを置かないでください。これはうまくいきません — obarrayに正しくシンボルを入力できるのはinternだけです。

Common Lispに関する注意: Common Lispとは異なりEmacs Lispは1つのシンボルを複数のobarrayにインターンする方法を提供しない。

以下の関数のほとんどは、引数に名前とobarrayをとります。名前が文字列以外、またはobarrayがベクター以外ならwrong-type-argumentエラーがシグナルされます。

Function: symbol-name symbol

この関数はsymbolの名前を文字列としてリターンする。たとえば:

(symbol-name 'foo)
     ⇒ "foo"

警告: 文字の置き換えにより文字列を変更すると、それはシンボルの名前を変更しますが、obarrayの更新には失敗するので行なわないこと!

Function: make-symbol name

この関数は新たに割り当てられた、名前がname(文字列でなかればならない)であるような、インターンされていないシンボルをリターンする。このシンボルの値と関数はvoidで、プロパティーリストはnil。以下の例ではsymの値はfooeqではない。なぜならこれは名前が‘foo’という、インターンされていないシンボルだからである。

(setq sym (make-symbol "foo"))
     ⇒ foo
(eq sym 'foo)
     ⇒ nil
Function: gensym &optional prefix

この関数はmake-symbolを使用してprefixgensym-counterを付加した名前のシンボルをリターンする。プレフィックスのデフォルトは"g"

Function: intern name &optional obarray

この関数は名前がnameであるような、インターンされたシンボルをリターンする。オブジェクト配列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にインターンできる。Emacs Lispではinternの引数はシンボルではなく文字列なのでこれを行なうことはできない。

Function: intern-soft name &optional obarray

この関数はobarray内の名前がnameのシンボル、obarrayにその名前のシンボルが存在しなければnilをリターンする。したがって与えられた名前のシンボルがすでにインターンされているかテストするために、intern-softを使用することができる。obarrayが省略されるとグローバル変数obarrayの値が使用される。

引数nameにはシンボルも使用できる。この場合、指定されたobarrayにnameがインターンされていればname、それ以外ならnilをリターンする。

(intern-soft "frazzle")        ; そのようなシンボルは存在しない
     ⇒ nil
(make-symbol "frazzle")        ; インターンされていないシンボルを作成する
     ⇒ frazzle
(intern-soft "frazzle")        ; そのようなシンボルは見つからない
     ⇒ nil
(setq sym (intern "frazzle"))  ; インターンされたシンボルを作成する
     ⇒ frazzle
(intern-soft "frazzle")        ; シンボルが見つかった!
     ⇒ frazzle
(eq sym 'frazzle)              ; そしてそれは同じシンボル
     ⇒ t
Variable: obarray

この変数はinternreadが使用する標準のobarrayである。

Function: mapatoms function &optional obarray

この関数はオブジェクト配列obarrayの中の各シンボルにたいして、functionを一度呼び出しその後nilをリターンする。obarrayが省略されると、通常のシンボルにたいする標準のオブジェクト配列obarrayの値がデフォルトになる。

(setq count 0)
     ⇒ 0
(defun count-syms (s)
  (setq count (1+ count)))
     ⇒ count-syms
(mapatoms 'count-syms)
     ⇒ nil
count
     ⇒ 1871

mapatomsを使用する他の例については、ドキュメント文字列へのアクセスdocumentationを参照のこと。

Function: unintern symbol obarray

この関数はオブジェクト配列obarrayからsymbolを削除する。obarrayの中にsymbolが存在ければ、uninternは何も行なわない。obarraynilなら現在のobarrayが使用される。

symbolにシンボルではなく文字列を与えると、それはシンボルの名前を意味する。この場合、uninternは(もしあれば)obarrayからその名前のシンボルを削除する。そのようなシンボルが存在するならuninternは何も行なわない。

uninternがシンボルを削除したらt、それ以外はnilをリターンする。


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

9.4 シンボルのプロパティ

シンボルはそのシンボルについての様々な情報を記録するために使用される、任意の数のシンボルプロパティー(symbol properties)をもつことができます。たとえばシンボルのrisky-local-variableプロパティーがnilなら、その変数の名前が危険なファイルローカル変数(ファイルローカル変数を参照)であることを意味します。

シンボルのプロパティーとプロパティー値はそれぞれ、シンボルのプロパティーリストセル(シンボルの構成要素を参照)に、プロパティーリスト形式(プロパティリストを参照)で格納されます。


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

9.4.1 シンボルのプロパティへのアクセス

以下の関数を使用してシンボルプロパティーにアクセスできます。

Function: get symbol property

この関数はsymbolのプロパティーリスト内の、名前がpropertyというプロパティーの値をリターンする。そのようなプロパティーが存在しなければnilをリターンする。したがって値がnilのときとプロパティーが存在しないときの違いはない。

名前propertyeqを使用して既存のプロパティーと比較されるので、すべてのオブジェクトがプロパティーとして適正である。

putの例を参照のこと。

Function: put symbol property value

この関数はsymbolのプロパティーリストの、プロパティー名propertyvalueを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))
Function: symbol-plist symbol

この関数はsymbolのプロパティーリストをリターンする。

Function: setplist symbol plist

この関数はsymbolのプロパティーリストをplistにセットする。plistは通常は適正なプロパティーリストであるべきだが、これは強制ではない。リターン値はplistです。

(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(abbrevとabbrev展開を参照)のメカニズムでこれを行なっている。

以下のようにsetplistplist-putputを定義できる:

(defun put (symbol prop value)
  (setplist symbol
            (plist-put (symbol-plist symbol) prop value)))
Function: function-get symbol property &optional autoload

この関数はgetと等価だがsymbolが関数のエイリアス名なら。実際の関数を命名するシンボルのプロパティリストを照合する点が異なる。関数の定義を参照のこと。オプション引数autoloadが非nilで、symbolが自動ロードされていれば、その自動ロードによりsymbolpropertyがセットされるかもしれないので、この関数はそれの自動ロードを試みるだろう。autoloadがシンボルmacroなら、symbolが自動ロードされたマクロのときだけ自動ロードを試みる。

Function: function-put function property value

この関数はfunctionpropertyvalueをセットする。functionはシンボルであること。関数のプロパティのセットには、putよりこの関数を呼び出すほうがよい。この関数を使用すれば、いつか古いプロパティから新しいプロパティへのリマップを実装することができるからである。


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

9.4.2 シンボルの標準的なプロパティ

Emacsで特別な目的のために使用されるシンボルプロパティーを以下に一覧します。以下のテーブルで、“命名される関数(the named function)”と言うときは、関数名がそのシンボルであるような関数を意味します。“命名される変数(the named variable)”等の場合も同様です。

:advertised-binding

このプロパティーリストは、命名される関数のドキュメントを表示する際に優先されるキーバインディングを指定する。ドキュメント内でのキーバインディングの置き換えを参照のこと。

char-table-extra-slots

値が非nilなら、それは命名される文字テーブル型の追加スロットの数を指定する。文字テーブルを参照のこと。

customized-face
face-defface-spec
saved-face
theme-face

これらのプロパティーはフェイスの標準のフェイス仕様(face specs)と、フォント仕様のsaved-fase、customized-face、themed-faceを記録するために使用される。これらのプロパティーを直接セットしないこと。これらのプロパティーはdeffaceと関連する関数により管理される。フェイスの定義を参照のこと。

customized-value
saved-value
standard-value
theme-value

これらのプロパティーは、カスタマイズ可能な変数のstandard-value、saved-value、customized-value(しかし保存はされない)、themed-valueを記録するために使用される。これらのプロパティーを直接セットしないこと。これらはdefcustomと関連する関数により管理される。カスタマイゼーション変数の定義を参照のこと。

disabled

値が非nilなら命名される関数はコマンドとして無効になる。コマンドの無効化を参照のこと。

face-documentation

値には命名されるフェイスのドキュメント文字列が格納される。これはdeffaceにより自動的にセットされる。フェイスの定義を参照のこと。

history-length

値が非nilなら、命名されるヒストリーリスト変数のミニバッファーヒストリーの最大長を指定する。ミニバッファーのヒストリーを参照のこと。

interactive-form

この値は命名される関数のインタラクティブ形式である。通常はこれを直接セットするべきではない。かわりにスペシャルフォームinteractiveを使用すること。インタラクティブな呼び出しを参照されたい。

menu-enable

この値は命名されるメニューアイテムが、メニュー内で有効であるべきか否かを決定するための式である。単純なメニューアイテムを参照のこと。

mode-class

値がspecialなら命名されるメジャーモードはspecial(特別)である。メジャーモードの慣習を参照のこと。

permanent-local

値が非nilなら命名される変数はバッファーローカル変数となり、メジャーモードの変更によって変数の値はリセットされない。バッファーローカルなバインディングの作成と削除を参照のこと。

permanent-local-hook

値が非nilなら、命名される関数はメジャーモード変更時にフック変数のローカル値から削除されない。フックのセットを参照のこと。

pure

値が非nilの場合には、名づけられた関数は純粋(pure)だとみなされる。定数の引数で呼び出された場合には、コンパイル時に評価することができる。これは実行時のエラーをコンパイル時へとシフトする。純粋ストレージ(pure storage)と混同しないこと(純粋ストレージを参照)。

risky-local-variable

値が非nilなら、命名される変数はファイルローカル変数としては危険だとみなされる。ファイルローカル変数を参照のこと。

safe-function

値が非nilなら、命名される関数は評価において一般的に安全だとみなされます。安全に関数を呼び出せるかどうかの判断を参照のこと。

safe-local-eval-function

値が非nilなら、命名される関数はファイルローカルの評価フォーム内で安全に呼び出すことができる。ファイルローカル変数を参照のこと。

safe-local-variable

値は命名される変数の、安全なファイルローカル値を決定する関数を指定する。ファイルローカル変数を参照のこと。

side-effect-free

nil値は命名される関数は副作用(関数とは?を参照)をもたないので、バイトコンパイラーは値が使用されない呼び出しを無視する。このプロパティの値がerror-freeなら、バイトコンパイラーはそのような呼び出しの削除すら行うかもしれない。バイトコンパイラーの最適化に加えて、このプロパティは関数の安全性を判断するためにも使用される(安全に関数を呼び出せるかどうかの判断を参照)。

undo-inhibit-region

nilの場合には、命名される関数の直後にundoが呼び出されると、undo操作をアクティブなリージョンに限定することを抑止する。アンドゥを参照のこと。

variable-documentation

nilなら、それは命名される変数のドキュメント文字列を指定する。ドキュメント文字列はdefvarと関連する関数により自動的にセットされる。フェイスの定義を参照のこと。


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

10 評価

Emacs Lispでの式の評価(evaluation)は、Lispインタープリター — 入力としてLispオブジェクトを受け取り、それの式としての値(value as an expression)を計算する — により処理されます。評価を行なう方法はそのオブジェクトのデータ型に依存していて、それはこのチャプターで説明するルールにより行なわれます。インタープリターはプログラムの一部を評価するために自動的に実行されますが、Lispプリミティブ関数のevalを通じて明示的に呼び出すこともできます。


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

10.1 評価の概要

Lispインタープリター(またはLispエバリュエーター)はEmacsの一部であり、与えられた式の値を計算します。Lispで記述された関数が呼び出されると、エバリュエーターはその関数のbody(本文)の中の式を評価してその関数の値を計算します。したがってLispプログラムを実行するとは、実際にはLispインタープリターを実行することを意味します。

評価を意図したLispオブジェクトはフォーム(form)、または式(expression)と呼ばれます6。フォームはデータオブジェクトであって単なるテキストではないという事実は、Lisp風の言語と通常のプログラミング言語との間にある基本的な相違点の1つです。任意のオブジェクトを評価できますが、実際に評価される事が非常に多いのは数字、シンボル、リスト、文字列です。

以降のセクションでは、各種フォームにたいしてそれを評価することが何を意味するかの詳細を説明します。

Lispフォームを読み取ってそのフォームを評価するのは、非常に一般的なアクティビティーですが、読み取りと評価は別のアクティビティーであって、どちらか一方を単独で処理することができます。読み取っただけでは何も評価されません。読み取りはLispオブジェクトのプリント表現をそのオブジェクト自体に変換します。そのオブジェクトが評価されるべきフォームなのか、そのれともまったく違う目的をもつかを指定するのは、readの呼び出し元の役目です。入力関数を参照してください。

評価とは再帰的な処理であり、あるフォームを評価するとそのフォームの一部が評価されるといったことがよくあります。たとえば(car x)のような関数呼び出し(function call)のフォームを評価する場合、Emacsは最初にその引数(サブフォームx)を評価します。引数を評価した後、Emacsはその関数(car)を実行(executes)します。その関数がLispで記述されていれば、関数のbody(本文)を評価することによって実行が行なわれます(しかしこの例で使用しているcarはLisp関数ではなくCで実装されたプリミティブ関数である)。関数と関数呼び出しについての情報は関数を参照してください。

評価は環境(environment)と呼ばれるコンテキストの内部で行なわれます。環境はすべてのLisp変数(変数を参照)のカレント値とバインディングにより構成されます。7フォームが新たなバインディングを作成せずに変数を参照する際、その変数はカレントの環境から与えられる値へと評価されます。フォームの評価は、変数のバインディングによって一時的にその環境を変更することもあります(ローカル変数を参照)。

フォームの評価が永続する変更を行なうこともあります。これらの変更は副作用(side effects)と呼ばれます。副作用を生成するフォームの例は(setq foo 1)です。

コマンドキー解釈での評価と混同しないでください。エディターのコマンドループはアクティブなキーマップを使用して、キーボード入力をコマンド(インタラクティブに呼び出すことができる関数)に変換してからそのコマンドを実行するために、call-interactivelyを使用します。そのコマンドがLispで記述されていれば、そのコマンドの実行には通常は評価を伴います。しかしこのステップはコマンドキー解釈の一部とは考えません。コマンドループを参照してください。


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

10.2 フォームの種類

評価される事を意図したLispオブジェクトはフォーム(form)、または式(expression))と呼ばれます。Emacsがフォームを評価する方法はフォームのデータ型に依存します。Emacsは3種の異なるフォーム — シンボル、リスト、およびその他すべての型 — をもち、それらが評価される方法は異なります。このセクションではまず最初に自己評価フォームのその他の型から開始して、3つの種類をすべて1つずつ説明します。


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

10.2.1 自己評価を行うフォーム

自己評価フォーム(self-evaluating form)はリストやシンボルではないすべてのフォームです。自己評価フォームはそのフォーム自身を評価します。評価の結果は評価されたオブジェクトと同じです。したがって数字の25は25、文字列"foo"は文字列"foo"に評価されます。同様にベクターの評価では、ベクターの要素の評価は発生しません — 内容が変更されずに同じベクターがリターンされます。

'123               ; 評価されずに表示される数字
     ⇒ 123
123                ; 通常どおり評価され、同じものがreturnされる
     ⇒ 123
(eval '123)        ; 手動での評価 — 同じものがreturnされる
     ⇒ 123
(eval (eval '123)) ; 2度評価しても何も変わらない。
     ⇒ 123

自己評価フォームはプログラムの一部となる値を生成します。これをsetcaraset、その他の類似操作を通じて変更しようと試みるべきではありません。Lispインタープリターがプログラム中の自己評価フォームにより生成される定数を統合して、これらの定数が構造を共有するかもしれません。可変性を参照してください。

自己評価されるという事実による利点から数字、文字、文字列、そしてベクターでさえLispコード内で記述されるのが一般的です。しかし入力構文がない型にたいしてこれを行なうのは極めて異例です。なぜなら、これらをテキスト的に記述する方法がないからです。Lispプログラムを使用してこれらの型を含むLisp式を構築することは可能です。以下は例です:

;; バッファーオブジェクトを含む式を構築する。
(setq print-exp (list 'print (current-buffer)))
     ⇒ (print #<buffer eval-ja.texi>)
;; それを評価する。
(eval print-exp)
     -| #<buffer eval-ja.texi>
     ⇒ #<buffer eval-ja.texi>

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

10.2.2 シンボルのフォーム

シンボルが評価されるときは変数として扱われます。それが値をもつなら結果はその変数の値になります。そのシンボルが変数としての値をもたなければ、Lispインタープリターはエラーをシグナルします。変数の使用法についての情報は変数を参照してください。

以降の例ではsetqでシンボルに値をセットしています。その後シンボルを評価してからをsetqに戻します。

(setq a 123)
     ⇒ 123
(eval 'a)
     ⇒ 123
a
     ⇒ 123

シンボルniltは特別に扱われるので、nilの値は常にniltの値は常にtになります。これらに他の値をセットしたり、他の値にバインドすることはできません。したがってこの2つのシンボルは、(たとえevalがそれらを他の任意のシンボルと同様に扱うとはいえ)自己評価フォームと同じように振る舞います。名前が‘:’で始まるシンボルも同じ方法で自己評価されます。そして、(通常は)値を変更できない点も同じです。変更不可な変数を参照してください。


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

10.2.3 リストフォームの分類

空ではないリストフォームは関数呼び出し、マクロ呼び出し、スペシャルフォームのいずれかで、それは1番目の引数にしたがいます。これら3種のフォームは、以下で説明するように異なる方法で評価されます。残りの要素は関数、マクロ、またはスペシャルフォームにたいする引数(arguments)を構成します。

空ではないリストを評価する最初のステップは、1番目の要素の確認です。この要素は単独でそのリストがどの種類のフォームなのかと、残りの引数をどのように処理するがを決定します。SchemeのようなLisp方言とは異なり、1番目の要素は評価されません。


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

10.2.4 シンボル関数インダイレクション

リストの最初の要素がシンボルなら、評価はそのシンボルの関数セルを調べて、元のシンボルの代わりに関数セルの内容を使用します。その内容が他のシンボルなら、シンボルではないものが得られるまでこのプロセスが繰り返されます。このプロセスのことをシンボル関数インダイレクション(symbol function indirection: indirectionは間接の意)と呼びます。シンボル関数インダイレクションについての情報は関数の命名を参照してください。

このプロセスの結果、シンボルの関数セルが同じシンボルを参照する場合には、無限ループを起こす可能性があります。それ以外なら最終的には非シンボルにたどりつき、それは関数か他の適切なオブジェクトである必要があります。

適切なオブジェクトとは、より正確にはLisp関数(ラムダ式)、バイトコード関数、プリミティブ関数、Lispマクロ、スペシャルフォーム、またはオートロードオブジェクトです。これらそれぞれの型については以降のセクションで説明します。これらの型以外のオブジェクトならEmacsはinvalid-functionエラーをシグナルします。

以下の例はシンボルインダイレクションのプロセスを説明するものです。わたしたちはシンボルの関数セルへの関数のセットにfset、関数セルの内容(関数セルの内容へのアクセスを参照)の取得にsymbol-functionを使用します。具体的にはfirstの関数セルにシンボルcarを格納して、シンボルfirstersteの関数セルに格納します。

;; この関数セルのリンクを構築する:
;;   -------------       -----        -------        -------
;;  | #<subr car> | <-- | car |  <-- | first |  <-- | erste |
;;   -------------       -----        -------        -------
(symbol-function 'car)
     ⇒ #<subr car>
(fset 'first 'car)
     ⇒ car
(fset 'erste 'first)
     ⇒ first
(erste '(1 2 3))   ; ersteにより参照される関数を呼び出す
     ⇒ 1

対照的に、以下の例ではシンボル関数インダイレクションを使用せずに関数を呼び出しています。なぜなら1番目の要素はシンボルではなく、無名Lisp関数(anonymous Lisp function)だからです。

((lambda (arg) (erste arg))
 '(1 2 3))
     ⇒ 1

関数自身を実行するとその関数のbodyを評価します。ここではersteを呼び出すとき、シンボル関数インダイレクションが行なわれています。

このフォームが使用されるのは稀であり、現在では推奨されていません。かわりに以下のように記述するべきです:

(funcall (lambda (arg) (erste arg))
         '(1 2 3))

または単に

(let ((arg '(1 2 3))) (erste arg))

ビルトイン関数のindirect-functionは、明示的にシンボル関数インダイレクションを処理するための簡単な方法を提供します。

Function: indirect-function function &optional noerror

この関数はfunctionが意味するものを関数としてリターンする。functionがシンボルならfunctionの関数定義を探して、その値で最初からやり直す。functionがシンボルでなければfunction自身をリターンする。

この関数は最終的なシンボルがバインドされていなければnilをリターンする。特定のシンボル内にループがれば、この関数はcyclic-function-indirectionエラーをシグナルする。

オペション引数noerrorは廃れており、後方互換のためだけのもので効果はない。

以下はLispでindirect-functionを定義する例である:

(defun indirect-function (function)
  (if (symbolp function)
      (indirect-function (symbol-function function))
    function))

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

10.2.5 関数フォームの評価

リストの1番目の要素がLispの関数オブジェクト、バイトコードオブジェクト、プリミティブ関数オブジェクトのいずれかと評価されると、そのリストは関数呼び出し(function call)になります。たとえば、以下は関数+を呼び出します:

(+ 1 x)

関数呼び出しを評価する最初のステップでは、そのリストの残りの要素を左から右に評価します。結果は引数の実際の値で、リストの各要素にたいして1つの値となります。次のステップでは関数apply(関数の呼び出しを参照)を使用して、引数のリストでその関数を呼び出します。関数がLispで記述されていたら引数はその関数の引数変数にバインドするために使用されます。その後に関数body内のフォームが順番に評価されて、リストのbodyフォームの値が関数呼び出しの値になります。


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

10.2.6 Lispマクロの評価

リストの最初の要素がマクロオブジェクトと評価されると、そのリストはマクロ呼び出し(macro call)になります。マクロ呼び出しが評価されるとき、リストの残りの要素は最初は評価されません。そのかわりこれらの要素自体がマクロの引数に使用されます。そのマクロ定義は、元のフォームが評価される場所で置換フォームを計算します。これをマクロの展開(expansion)と言います。展開した結果は、任意の種類のフォーム — 自己評価定数、シンボル、リストになります。展開した結果自体がマクロ呼び出しなら、結果が他の種類のフォームになるまで、繰り返し展開処理が行なわれます。

通常のマクロ展開は、その展開結果を評価することにより終了します。しかし他のプログラムもマクロ呼び出しを展開し、それらが展開結果を評価するか、あるいは評価しないかもしれないので、そのマクロ展開が即時または最終的に評価される必要がない場合があります。

引数式は通常はマクロ展開の計算の一部としては評価されませんが、展開の部分として出現するので、展開結果が評価されるときに計算されます。

たとえば以下のようなマクロ定義が与えられたとします:

(defmacro cadr (x)
  (list 'car (list 'cdr x)))

(cadr (assq 'handler list))のような式はマクロ呼び出しであり、展開結果は以下のようになります:

(car (cdr (assq 'handler list)))

引数(assq 'handler list)が展開結果に含まれることに注意してください。

Emacs Lispマクロの完全な説明はマクロを参照してください。


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

10.2.7 スペシャルフォーム

スペシャルフォーム(special form)とは、特別だとマークされたプリミティブ関数であり、その引数のすべては評価されません。もっとも特別なフォームは制御構文の定義や変数バインディングの処理等、関数ではできないことを行ないます。

スペシャルフォームはそれぞれ、どの引数を評価して、どの引数を評価しないかについて独自のルールをもちます。特定の引数が評価されるかどうかは、他の引数を評価した結果に依存します。

式の最初のシンボルがスペシャルフォームなら、式はそのスペシャルフォームのルールにしたがう必要があります。それ以外ならEmacsの挙動は(たとえクラッシュしなくいとしても)未定義です。たとえば((lambda (x) x . 3) 4)lambdaで始まるサブ式を含みますが、これは適正なlambda式ではないので、Emacsはエラーをシグナルするかもしれないし、3や4やnilをリターンしたり、もしかしたら他の挙動を示すかもしれません。

Function: special-form-p object

この述語は引数がスペシャルフォームかをテストして、スペシャルフォームならt、それ以外ならnilをリターンする。

以下にEmacs Lispのスペシャルフォームすべてと、それらがどこで説明されているかのリファレンスをアルファベット順でリストします。

and

see section 組み合わせ条件の構築

catch

see section 明示的な非ローカル脱出: catchthrow

cond

see section 条件

condition-case

see section エラーを処理するコードの記述

defconst

see section グローバル変数の定義

defvar

see section グローバル変数の定義

function

see section 無名関数

if

see section 条件

interactive

see section インタラクティブな呼び出し

lambda

see section ラムダ式

let
let*

see section ローカル変数

or

see section 組み合わせ条件の構築

prog1
prog2
progn

see section 順序

quote

see section クォート

save-current-buffer

see section カレントバッファー

save-excursion

see section エクスカーション

save-restriction

see section ナローイング

setq

see section 変数の値のセット

setq-default

see section バッファーローカルなバインディングの作成と削除

unwind-protect

see section 非ローカル脱出

while

see section 繰り返し

Common Lispに関する注意: GNU EmacsとCommon Lispのスペシャルフォームを比較する。setqifcatchはEmacs LispとCommon Lispの両方でスペシャルフォームである。save-excursionはEmacs Lispではスペシャルフォームだが、Common Lispには存在しない。throwはCommon Lispではスペシャルフォーム(なぜなら複数の値をthrowできなければならない)だが、Emacs Lispでは(複数の値をもたない)関数である。


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

10.2.8 自動ロード

オートロード(autoload)機能により、まだ関数定義がEmacsにロードされていない関数(またはマクロ)を呼び出すことができます。オートロードは定義がどのファイルに含まれるかを指定します。オートロードオブジェクトがシンボルの関数定義にある場合は、関数としてそのシンボルを呼び出すことにより、自動的に指定されたファイルがロードされます。その後にファイルからロードされた実際の定義を呼び出します。シンボル内の関数定義としてオートロードオブジェクトをアレンジする方法はautoloadで説明します。


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

10.3 クォート

スペシャルフォームquoteは、単一の引数を記述されたままに評価せずにリターンします。これはプログラムに自己評価オブジェクトではない、定数シンボルや定数リストを含める方法を提供します(数字、文字列、ベクターのような自己評価オブジェクトをクォートする必要はない)。

Special Form: quote object

このスペシャルフォームはobjectを評価せずにリターンする。リターン値は共有されるかもしれないので変更しないこと。自己評価を行うフォームを参照のこと。

quoteはプログラム中で頻繁に使用されるので、Lispはそれにたいする便利な入力構文を提供します。アポストロフィー文字(‘'’)に続けてLispオブジェクト(の入力構文)を記述すると、それは1番目の要素がquote、2番目の要素がそのオブジェクトであるようなリストに展開されます。つまり入力構文'x(quote x)の略記になります。

以下にquoteを使用した式の例をいくつか示します:

(quote (+ 1 2))
     ⇒ (+ 1 2)
(quote foo)
     ⇒ foo
'foo
     ⇒ foo
''foo
     ⇒ 'foo
'(quote foo)
     ⇒ 'foo
['foo]
     ⇒ ['foo]

(list '+ 1 2)'(+ 1 2)の2つの式はいずれも(+ 1 2)とequalなリストを生成しますが前者はmutableリストを新たに作成するのにたいして、後者は共有される可能性のある変更すべきではないコンスから構築したリストを作成します。自己評価を行うフォームを参照してください。

他のクォート構文としては、コンパイル用にLispで記述された無名のラムダ式の元となるfunction (無名関数を参照)、リストを計算して置き換える際にリストの一部だけをクォートするために使用される‘`’(バッククォートを参照)があります。


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

10.4 バッククォート

バッククォート構文(backquote constructs)を使用することにより、リストをクォートしてそのリストのある要素を選択的に評価することができます。もっとも簡単な使い方ではスペシャルフォーム quote (前セクションで説明済み。クォートを参照)。 たとえば以下の2つのフォームは同じ結果を生みます:

`(a list of (+ 2 3) elements)
     ⇒ (a list of (+ 2 3) elements)
'(a list of (+ 2 3) elements)
     ⇒ (a list of (+ 2 3) elements)

バッククォートする引数の内側でスペシャルマーカー‘,’を使用すると、それは値が定数でないことを示します。Emacs Lispエバリュエーターは‘,’がついた引数を放置して、リスト構文内にその値を配置します:

`(a list of ,(+ 2 3) elements)
     ⇒ (a list of 5 elements)

,’による置き換えを、リスト構文のより深いレベルでも使用できます。たとえば:

`(1 2 (3 ,(+ 4 5)))
     ⇒ (1 2 (3 9))

スペシャルマーカー‘,@’を使用すれば、評価された値を結果リストに継ぎ足す(splice)こともできます。継ぎ足されたリストの要素は、結果リスト内の他の要素と同じレベルになります。‘`’を使用しない等価なコードは読むのが困難なことがよくあります。以下にいくつかの例を示します:

(setq some-list '(2 3))
     ⇒ (2 3)
(cons 1 (append some-list '(4) some-list))
     ⇒ (1 2 3 4 2 3)
`(1 ,@some-list 4 ,@some-list)
     ⇒ (1 2 3 4 2 3)

(setq list '(hack foo bar))
     ⇒ (hack foo bar)
(cons 'use
  (cons 'the
    (cons 'words (append (cdr list) '(as elements)))))
     ⇒ (use the words foo bar as elements)
`(use the words ,@(cdr list) as elements)
     ⇒ (use the words foo bar as elements)

バッククォート構文の部分式に置換や継ぎ足し(splice)がなければ、これは共有される可能性があり変更するべきではないコンス、ベクター、文字列でのquoteのように振る舞います。自己評価を行うフォームを参照してください。


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

10.5 evalについて

フォームはほとんどの場合、実行されるプログラム内に出現することにより自動的に評価されます。ごく稀に実行時 — たとえば編集されているテキストやプロパティーリストから取得したフォームを読み取った後 — に計算されるようにフォームを評価するコードを記述する必要があるかもしれません。このようなときはeval関数を使用します。evalが不必要だったり、かわりに他の何かを使用すべきときがよくあります。たとえば変数から値を取得するにはevalも機能しますが、symbol-valueのほうが適しています。evalで評価するためにプロパティーリストに式を格納するかわりに、funcallに渡すように関数を格納した方がよいでしょう。

このセクションで説明する関数と変数はフォームの評価、評価処理の制限の指定、最後にリターンされた値の記録を行なうものです。ファイルのロードでも評価が行なわれます(ロードを参照)。

データ構造に式を格納して評価するより、データ構造に関数を格納してfuncallapplyで呼び出すほうが、より明解で柔軟です。関数を使用することにより、引数に情報を渡す能力が提供されます。

Function: eval form &optional lexical

これは式を評価する基本的な関数である。この関数はカレント環境内でformを評価して、その結果をリターンする。formオブジェクトの型はそれが評価される方法を決定します。フォームの種類を参照のこと。

引数lexicalは、ローカル変数にたいするスコープ規則(変数のバインディングのスコーピングルールを参照)を指定する。これが省略またはnilならデフォルトのダイナミックスコープ規則を使用してformを評価することを意味する。tならレキシカルスコープ規則が使用されることを意味する。lexicalの値にはレキシカルバインディングでの特定のレキシカル環境(lexical environment)を指定する空ではないalistも指定できる。しかしこの機能はEmacs Lispデバッガーのような、特別な用途にたいしてのみ有用。レキシカルバインディングを参照のこと。

evalは関数なのでeval呼び出しに現れる引数式は2回 — evalが呼び出される前の準備で一度、eval関数自身によりもう一度 — 評価される。以下に例を示す:

(setq foo 'bar)
     ⇒ bar
(setq bar 'baz)
     ⇒ baz
;; evalが引数fooを受け取る
(eval 'foo)
     ⇒ bar
;; evalが、fooの値である、引数barを受け取る
(eval foo)
     ⇒ baz

evalで現在アクティブな呼び出しの数はmax-lisp-eval-depthに制限される(以下参照)。

Command: eval-region start end &optional stream read-function

この関数はカレントバッファー内の、位置startendで定義されるリージョン内のフォームを評価する。この関数はリージョンからフォームを読み取ってevalを呼び出す。これはリージョンの最後に達するか、処理されないエラーがシグナルされるまで行なわれる。

デフォルトではeval-regionは出力を何も生成しない。しかしstreamが非nilなら出力関数(出力関数を参照)で生成された任意の出力、同様にリージョン内の式を評価した結果の値が、streamを使用してプリントされる。出力ストリームを参照のこと。

read-functionが非nilなら、readのかわりに1つずつ式を読み取るために使用する関数を指定すること。これは入力を読み取るストリームを指定する、1つの引数で呼び出される関数である。この関数を指定するために変数load-read-function(How Programs Do Loadingを参照)も使用できるが、引数read-functionを使用するほうが堅実である。

eval-regionはポイントを移動しない。常にnilをリターンする。

Command: eval-buffer &optional buffer-or-name stream filename unibyte print

この関数はeval-regionと似ているが、引数は異なるオプション機能を提供する。eval-bufferはバッファーbuffer-or-nameのアクセス可能な部分(Narrowing in The GNU Emacs Manualを参照)の全体を処理する。buffer-or-nameにはバッファー名(文字列)を指定でき、nil(または省略)のときはカレントバッファーを意味する。streamが非nil、またはprintnilなら、eval-regionのようにstreamが使用される。この場合には式の評価結果の値は依然として破棄されるが、出力関数による出力はエコーエリアにプリントされる。filenameload-history (アンロードを参照)に使用されるファイル名であり、デフォルトはbuffer-file-name (バッファーのファイル名を参照)。unibyteが非nilならread可能な限りは文字列をユニコードに変換する。

eval-current-bufferはこのコマンドのエイリアスである。

User Option: max-lisp-eval-depth

この変数はエラー(エラーメッセージは"Lisp nesting exceeds max-lisp-eval-depth")がシグナルされる前にevalapplyfuncallの呼び出しで許容される最大の深さを定義する。

制限を超過時のエラーを付随するこの制限は、誤って定義された関数による無限再帰をEmacs Lispが回避する方法の1つである。max-lisp-eval-depthの値を過大に増加させると、そのようなコードはかわりにスタックオーバーフローを起こすだろう。オーバーフローを処理できるシステムがいくつかある。この場合には通常のLisp評価は割り込まれて、制御はトップレベルのコマンドループ(top-level)に戻される。この状況ではEmacs Lispデバッガにエンターする手段は存在しないことに注意されたい。エラーによるデバッガへのエンターを参照のこと。

Lisp式に記述された関数の呼び出し、関数呼び出しの引数と関数bodyフォームにたいする再帰評価、Lispコード内での明示的な呼び出し等では内部的にevalapplyfuncallを使用して深さ制限を計数する。

この変数のデフォルト値は800。この値を100未満にセットした場合には、値が与えられた値に達するとLispはそれを100にリセットする。空きが少なければデバッガー自身を実行するために空きが必要になるので、Lispデバッガーに入ったときは値が増加される。

max-specpdl-sizeはネストの他の制限を提供する。Local Variablesを参照のこと。

Variable: values

この変数の値は読み取り、評価、プリントを行なった標準的なEmacsコマンドにより、バッファー(ミニバッファーを含む)からリターンされる値のリストである(これには*ielm*バッファーでの評価や、lisp-interaction-modeでのC-jC-x C-e、類似の評価コマンドを使用した評価は含まれないことに注意)。要素の順番はもっとも最近のものが最初になる。

(setq x 1)
     ⇒ 1
(list 'A (1+ 2) auto-save-default)
     ⇒ (A 3 t)
values
     ⇒ ((A 3 t) 1 …)

この変数は最近評価されたフォームの値を後で参照するのに有用。values自体の値のプリントは、値がおそらく非常に長くなるので通常は悪いアイデアである。かわりに以下のように特定の要素を調べること:

;; もっとも最近評価された結果を参照する
(nth 0 values)
     ⇒ (A 3 t)
;; これは新たな要素をputするので
;;   すべての要素が1つ後に移動する
(nth 1 values)
     ⇒ (A 3 t)
;; これは次に新しい、この例の前の次に新しい要素を取得する
(nth 3 values)
     ⇒ 1

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

10.6 遅延されたLazy評価

たとえばプログラムの将来において計算結果が不要なら時間を要する計算処理を回避したい等、式の評価を遅延できれば便利な場合があります。そのような遅延評価(deferred evaluation)をサポートするために、thunkは以下の関数とマクロを提供します。

Macro: thunk-delay forms…

formsを評価するためのthunkをリターンする(訳注: thunkとは別のサブルーチンに計算を追加で挿入するために使用するサブルーチンであり、計算結果が必要になるまで計算を遅延したり、別のサブルーチンの先頭や最後に処理を挿入するために使用される。英語版Wikipediaより)。thunkはthunk-delay呼び出しのlexical環境を継承するクロージャである(クロージャーを参照)。このマクロの使用にはlexical-bindingが必要。

Function: thunk-force thunk

thunkを作成したthunk-delayで指定されたフォームの評価をthunkに強制する。最後のフォームの評価結果をリターンする。thunkが強制されたことも“記憶”される。同一のthunkにたいする以降のthunk-force呼び出しでは、フォームを再度評価せずに同じ結果をリターンする。

Macro: thunk-let (bindings…) forms…

このマクロはletの類似だが“lazy(遅延された)”変数バインディングを作成する。すべてのバインディングは(symbol value-form)という形式をもつ。letとは異なり、すべてのvalue-formの評価はformsを最初に評価する際に、対応するsymbolのバインディングが使用されるまで遅延される。すべてのvalue-formは最大でも1回評価される。このマクロの使用にはlexical-bindingが必要。

例:

(defun f (number)
  (thunk-let ((derived-number
              (progn (message "Calculating 1 plus 2 times %d" number)
                     (1+ (* 2 number)))))
    (if (> number 10)
        derived-number
      number)))

(f 5)
⇒ 5

(f 12)
-| Calculating 1 plus 2 times 12
⇒ 25

遅延バインドされた変数の特性として、それらにたいする(setqによる)セットはエラーになります。

Macro: thunk-let* (bindings…) forms…

これはthunk-letと似ているが、bindings内の任意の式がこのthunk-let*フォーム内の先行するバインディングの参照を許されている点が異なる。このマクロの使用にはlexical-bindingが必要。

(thunk-let* ((x (prog2 (message "Calculating x...")
                    (+ 1 1)
                  (message "Finished calculating x")))
             (y (prog2 (message "Calculating y...")
                    (+ x 1)
                  (message "Finished calculating y")))
             (z (prog2 (message "Calculating z...")
                    (+ y 1)
                  (message "Finished calculating z")))
             (a (prog2 (message "Calculating a...")
                    (+ z 1)
                  (message "Finished calculating a"))))
  (* z x))

-| Calculating z...
-| Calculating y...
-| Calculating x...
-| Finished calculating x
-| Finished calculating y
-| Finished calculating z
⇒ 8

thunk-letthunk-let*はthunkを暗黙に使用します。これらの拡張はヘルパーシンボルを作成してバインディング式をラップするthunkにバインドします。forms本体中の元の変数にたいするすべての参照は、対応するヘルパー変数を引数とするthunk-force呼び出し式に置き換えられます。したがってthunk-letthunk-let*を使用するコードはthunkを使用するように書き換えが可能ですが、多くの場合には明示的にthunkを使用するよりこれらのマクロを使用するほうが優れたコードになるでしょう。


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

11 制御構造

Lispプログラムは一連の、あるいはフォーム (フォームの種類を参照)により形成されます。これらのフォームの実行順は制御構造(control structures)で囲むことによって制御します。制御構造とはその制御構造が含むフォームをいつ、どのような条件で、何回実行するかを制御するスペシャルフォームです。

もっとも単純な実行順は1番目はa、2番目はb、...というシーケンシャル実行(sequential execution: 順番に実行)です。これは関数のbody内の連続する複数のフォームや、Lispコードのファイル内のトップレベルを記述したときに発生します — つまりフォームは記述した順に実行されます。わたしたちはこれをテキスト順(textual order)と呼びます。たとえば関数のbodyが2つのフォームabから構成される場合、関数の評価は最初にa、次にbを評価します。bを評価した結果がその関数の値となります。

明示的に制御構造を使用することにより、非シーケンシャルな順番での実行が可能になります。

Emacs Lispは他の様々な順序づけ、条件、繰り返し、(制御された)ジャンプを含む複数の種類の制御構造を提供しており、以下ではそれらのすべてを記述します。ビルトインの制御構造は制御構造のサブフォームが評価される必要がなかったり、順番に評価される必要がないのでスペシャルフォームです。独自の制御構造を構築するためにマクロを使用することができます(マクロを参照)。


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

11.1 順序

フォームを出現順に評価するのは、あるフォームから別のフォームに制御を渡すもっとも一般的な制御です。関数のbodyのようなコンテキストにおいては自動的にこれが行なわれます。他の場所ではこれを行なうために制御構造を使用しなければなりません。Lispで一単純な制御構造はprognです。

スペシャルフォームprognは以下のようなものです:

(progn a b c …)

これは順番にabc、...を実行するよう指定します。これらはprognフォームのbodyと呼ばれます。body内の最後のフォームの値がprogn全体の値になります。(progn)nilをリターンします。

初期のLispではprognは、連続で複数のフォームを実行して最後のフォームの値を使用する唯一の方法でした。しかしプログラマーは関数のbodyの、(その時点では)1つのフォームだけが許される場所でprognを使用する必要が多いことに気づきました。そのため関数のbodyを暗黙のprognにして、prognのbodyのように複数のフォームを記述できるようにしました。他の多くの制御構造も暗黙のprognを同様に含みます。結果として昔ほどprognは多用されなくなりました。現在ではprognが必要になるのはunwind-protectandor、またはifthenパートの中であることがほとんどです。

Special Form: progn forms…

このスペシャルフォームはformsのすべてをテキスト順に評価してフォームの結果をリターンする。

(progn (print "The first form")
       (print "The second form")
       (print "The third form"))
     -| "The first form"
     -| "The second form"
     -| "The third form"
⇒ "The third form"

他の2つの構文は一連のフォームを同様に評価しますが、異なる値をリターンします:

Special Form: prog1 form1 forms…

このスペシャルフォームはform1formsのすべてをテキスト順に評価してform1の結果をリターンする。

(prog1 (print "The first form")
       (print "The second form")
       (print "The third form"))
     -| "The first form"
     -| "The second form"
     -| "The third form"
⇒ "The first form"

以下の例は変数xのリストから1番目の要素を削除して、削除した1番目の要素の値をリターンする:

(prog1 (car x) (setq x (cdr x)))
Special Form: prog2 form1 form2 forms…

このスペシャルフォームはform1form2、その後のformsのすべてをテキスト順で評価してform2の結果をリターンする。

(prog2 (print "The first form")
       (print "The second form")
       (print "The third form"))
     -| "The first form"
     -| "The second form"
     -| "The third form"
⇒ "The second form"

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

11.2 条件

条件による制御構造は候補の中から選択を行ないます。Emacs Lispは5つの条件フォームをもちます。ifは他の言語のものとほとんど同じです。whenunlessifの変種です。condは一般化されたcase命令です。condを汎用化したものがpcaseです(パターンマッチングによる条件を参照)。

Special Form: if condition then-form else-forms…

ifconditionの値にもとづきthen-formelse-formsを選択する。評価されたconditionが非nilならthen-formが評価されて結果がリターンされる。それ以外ならelse-formsがテキスト順に評価されて最後のフォームの値がリターンされる(ifelseパートは暗黙のprognの例である。順序を参照)。

conditionの値がnilelse-formsが与えられなければ、ifnilをリターンする。

選択されなかったブランチは決して評価されない — 無視される — ので、ifはスペシャルフォームである。したがって以下の例ではprintが呼び出されることはないのでtrueはプリントされない。

(if nil
    (print 'true)
  'very-false)
⇒ very-false
Macro: when condition then-forms…

これはelse-formsがなく、複数のthen-formsが可能なifの変種である。特に、

(when condition a b c)

は以下と完全に等価である

(if condition (progn a b c) nil)
Macro: unless condition forms…

これはthen-formがないifの変種です:

(unless condition a b c)

は以下と完全に等価である

(if condition nil
   a b c)
Special Form: cond clause…

condは任意個数の選択肢から選択を行なう。cond内の各clauseはリストでなければならない。このリストのCARconditionで、(もしあれば)残りの要素はbody-formsとなる。したがってclauseは以下のようになる:

(condition body-forms…)

condは各clauseのconditionを評価することにより、テキスト順でclauseを試みる。conditionの値が非nilならそのclauseは成り立つ。その後にcondはそのclauseのbody-formsを評価して、body-formsの最後の値をリターンする。残りのclauseは無視される。

conditionの値がnilならそのclauseは失敗して、condは次のclauseに移動してそれのconditionを試みる。

clauseは以下のようにも見えるかもしれない:

(condition)

conditionがテストされたときに非nilなら、condフォームはconditionの値をリターンする。

すべてのconditionnilに評価された場合 — つまりすべてのclauseが不成立なら、condnilをリターンする。

以下の例はxの値が数字、文字列、バッファー、シンボルなのかをテストする4つのclauseをもつ:

(cond ((numberp x) x)
      ((stringp x) x)
      ((bufferp x)
       (setq temporary-hack x) ; 1つのclauseに
       (buffer-name x))        ; 複数bodyフォーム
      ((symbolp x) (symbol-value x)))

前のclauseが不成立のとき最後の条項を実行したいときがよくある。これを行なうには(t body-forms)のように、conditionの最後のclauseにtを使用する。フォームttに評価され決してnilにならないので、このclauseが不成立になることはなく最終的にcondはこのclauseに到達する。たとえば:

(setq a 5)
(cond ((eq a 'hack) 'foo)
      (t "default"))
⇒ "default"

このcond式はaの値がhackならfoo、それ以外は文字列"default"をリターンする。

すべての条件構文はcondifのいずれかで表すことができます。したがってどちらを選択するかはスタイルの問題になります。たとえば:

(if a b c)
≡
(cond (a b) (t c))

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

11.3 組み合わせ条件の構築

このセクションでは複雑な条件を表現するためにifcondとともによく使用される構文を説明します。andorの構文は、ある種の複数条件の構文として個別に使用することもできます。

Function: not condition

この関数はconditionが偽であることをテストする。この関数はconditionnilならt、それ以外はnilをリターンする。関数notnullと等価であり、空のリストをテストする場合はnullの使用を推奨する。

Special Form: and conditions…

スペシャルフォームandは、すべてのconditionsが真かどうかをテストする。この関数はconditionsを記述順に1つずつ評価することにより機能する。

あるconditionsnilに評価されると、残りのconditionsに関係なく、andnilをリターンしなければならない。この場合andは即座にnilをリターンして、残りのconditionsは無視される。

すべてのconditionsが非nilなら、それらの最後の値がandフォームの値になる。conditionsがない単独の(and)tをリターンする。なぜならすべてのconditionsが非nilとなるので、これは適切である(考えてみてみよ、非nilでないconditionsはどれか?)。

以下に例を示す。1番目の条件は整数1をリターンし、これはnilではまい。同様に2番目の条件は整数2をリターンし、これもnilではない。3番目の条件はnilなので、のこりの条件が評価されることは決してない。

(and (print 1) (print 2) nil (print 3))
     -| 1
     -| 2
⇒ nil

以下はandを使用した、より現実的な例である:

(if (and (consp foo) (eq (car foo) 'x))
    (message "foo is a list starting with x"))

(consp foo)nilをリターンすると、(car foo)は実行されないのでエラーにならないことに注意。

ifcondのいずれかを使用して、and式を記述することもできる。以下にその方法を示す:

(and arg1 arg2 arg3)
≡
(if arg1 (if arg2 arg3))
≡
(cond (arg1 (cond (arg2 arg3))))
Special Form: or conditions…

スペシャルフォームorは、少なくとも1つのconditionsが真かどうかをテストする。この関数はすべてのconditionsを1つずつ、記述された順に評価することにより機能する。

あるconditionsが非nil値に評価されたら、orの結果は非nilでなければならない。この場合orは即座にリターンし、残りのconditionsは無視される。この関数がリターンする値は、非nil値に評価された条件の値そのものである。

すべてのconditionsnilなら、or式はnilをリターンします。conditionsのない単独の(or)nilをリターンする。なぜならすべてのconditionsnilになるのでこれは適切である(考えてみよ、nilでないconditionsはどれか?)。

たとえば以下の式は、xnilか整数0かどうかをテストする:

(or (eq x nil) (eq x 0))

and構文と同様に、orcondに置き換えて記述することができる。たとえば:

(or arg1 arg2 arg3)
≡
(cond (arg1)
      (arg2)
      (arg3))

ほとんどの場合は、orifに置き換えて記述できるが完全ではない:

(if arg1 arg1
  (if arg2 arg2
    arg3))

これは完全に同一ではない。なぜならarg1arg2を2回評価するかもしれないからである。対照的に(or arg1 arg2 arg3)が2回以上引数を評価することは決してない。

Function: xor condition1 condition2

この関数はcondition1condition2の排他的論理和をリターンする。つまりxorは引数がいずれもnilあるいは非nilならnilをリターンする。それ以外なら非nilの引数の値をリターンする。

orとは対照的に引数はどちらも常に評価されることに注意。


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

11.4 パターンマッチングによる条件

4つの基本的な条件フォームとは別に、Emacs Lispにはcondcl-case (Conditionals in Common Lisp Extensionsを参照)の合成物とも言うべき、pcaseマクロというパターンマッチングによる条件フォームがあります。これはcondcl-caseの制限を克服して、パターンマッチングによるプログラミングスタイル(pattern matching programming style)を導入するものです。そのpcaseが克服する制限とは:

pcaseマクロはパターンマッチング(pattern matching)の変種であるような等価性テストを汎化したものによるconditionの置き換え、clauseの述語を簡潔に表現できるような機能の追加、clauseの述語とbody-formsの間でletバインディングを共有するようなアレンジにより、概念的には最初の引数のフォーカスではcl-case、clauseの処理フローではcondを借用しています。

この述語の簡潔な表現はパターン(pattern)として知られています。最初の引数の値にたいして呼び出される述語が非nilをリターンしたときには、“パターンが値にマッチした”といいます(“値がパターンにマッチした”ということもある)。


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

11.4.1 pcaseマクロ

背景はパターンマッチングによる条件を参照してください。

Macro: pcase expression &rest clauses

clauses内のclauseは(pattern body-forms…)という形式をもつ。

expressionの値( expval )を決定するために評価する。patternexpvalにマッチするような最初のclauseを探して、そのclauseのbody-formsに制御を渡す。

マッチが存在すればpcaseの値はマッチが成功したclauseのbody-formsの最後の値、それ以外ならpcasenilに評価される。

patternpcaseパターン(pcase pattern)である必要があります。これは以下に定義されるコアパターンのいずれか、またはpcase-defmacro (pcaseの拡張を参照)を通じて定義されるパターンの1つを使用できます。

このサブセクションの残りの部分ではコアパターンの異なるフォームをいくつかの例を交えて説明して、いくつかのパターンフォームが提供するletバイディング機能を使用する上で重要な注意点で締めくくります。コアパターンは以下のフォームをもつことができます:

_

任意のexpvalにマッチ。これはdon’t care、あるいはワイルドカード(wildcard)としても知られる。

'val

expvalvalが等しければマッチ。比較はequalのように行われる(同等性のための述語を参照)。

keyword
integer
string

expvalがリテラルオブジェクトと等しければマッチ。これは上述の'valの特殊なケースであり、これらのタイプのリテラルオブジェクトが自己クォート(self-quoting)を行うために可能となる。

symbol