Node:Top, Next:, Previous:(dir), Up:(dir)


Node:Copying, Next:, Previous:Top, Up:Top

GNU一般公有使用許諾書

1991年6月 バージョン2.0

Copyright © 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA 1

何人も、以下の内容を変更しないでそのまま複写する場合に限り、
本使用許諾書を複製したり頒布することができます。

はじめに

ほとんどのソフトウェアの使用許諾は、ソフトウェアを共有し、 変更するユーザの自由を奪うことを意図しています。 それに対して、我々のGNU一般公有使用許諾は、 フリー・ソフトウェアを共有したり変更する自由をユーザに保証するためのもの、 即ちフリー・ソフトウェアがそのユーザ全てにとって フリーであることを保証するためのものです。 本使用許諾は、Free Software Foundationのほとんど全てのソフトウェアに 適用されるだけでなく、 プログラムの作成者が本使用許諾に依るとした場合のそのプログラムにも 適用することができます。 (その他の Free Software Foundation のソフトウェアのいくつかは、 本許諾書ではなく、GNUライブラリ一般公有使用許諾で保護されます。) あなたは自分のプログラムにもこれを適用できます。

我々がフリー・ソフトウェアについて言う場合は 自由のことに言及しているのであって、価格のことではありません。 我々の一般公有使用許諾の各条項は、次の事柄を確実に実現することを 目的として立案されています。

このようなユーザの権利を守るために、我々は、 何人もこれらの権利を否定したり、あるいは放棄するように ユーザに求めることはできないという制限条項を設ける必要があります。 これらの制限条項は、ユーザが、フリー・ソフトウェアの複製物を 頒布したり変更しようとする場合には、そのユーザ自身が守るべき義務ともなります。

例えば、あなたがフリー・ソフトウェアの複製物を頒布する場合、 有償か無償かにかかわらず、 あなたは自分の持っている権利を全て相手に与えなければなりません。 あなたは、相手もまたソース・コードを受け取ったり入手できるということを 認めなければなりません。 さらにあなたは、彼らが自分たちの権利を知るように、 これらの条項を知らしめなければなりません。

 我々は次の2つの方法でユーザの権利を守ります。 (1)ソフトウェアに著作権を主張し、 (2)本使用許諾の条項の下で ソフトウェアを複製・頒布・変更する権利をユーザに与えます。

また、各作成者や我々自身を守るために、 本フリー・ソフトウェアが無保証であることを 全ての人々が了解している必要があります。 さらに、他の誰かによって変更されたソフトウェアが頒布された場合、 受領者はそのソフトウェアがオリジナル・バージョンではないということを 知らされる必要があります。 それは、他人の関与によって原開発者に対する評価が 影響されないようにするためです。

最後に、どのフリー・プログラムもソフトウェア特許に絶えず脅かされています。 我々は、フリー・プログラムの再頒布者が個人的に特許権を取得し、 事実上そのプログラムを自分の財産にしてしまうという危険を 避けたいと願っています。 これを防ぐために我々は、いずれの特許も、 誰でも自由に使用できるように使用許諾されるべきか、 あるいは何人に対しても全く使用させないかの、 いずれかにすべきであることを明らかにしてきました。

複写・頒布・変更に対する正確な条項と条件を次に示します。

  1. 本使用許諾は、本一般公有使用許諾の各条項に従って頒布されるという 著作権者からの告知文が表示されているプログラムやその他の作成物に適用されます。 以下において「プログラム」とは、そのようなプログラムや作成物を指すものとし、 また、「プログラム生成物」とは、上述した「プログラム」自身、または、 著作権法下における全ての派生物;すなわち、その「プログラム」の全部又は一部を、 そのまま又は変更して、且つ/又は他の言語に変換して、 内部に組み込んだ作成物を意味します。 (以下、言語変換は「変更」という用語の中に無条件に含まれるものとします。) 本使用許諾によって許諾を受ける者を「あなた」と呼びます。 

    複製、頒布、変更以外の行為は本使用許諾の対象としません。 それらは本使用許諾の範囲外です。 「プログラム」を実行させる行為に関して制約はありません。 「プログラム」の出力は、 (「プログラム」を実行させて作成させたかどうかとは無関係に) その内容が「プログラム生成物」である場合に限り本使用許諾の対象となります。 これが当てはまるかどうかは、「プログラム」が何をするものかに依ります。

  2. あなたは、どのような媒体上へ複製しようとする場合であっても、 入手した「プログラム」のソース・コードを そのままの内容で複写した上で適正な著作権表示と保証の放棄を明確、 且つ適正に付記する場合に限り、複製又は頒布することができます。 その場合、本使用許諾及び無保証に関する記載部分は、 全て元のままの形で表示してください。 また、「プログラム」の頒布先に対しては、 「プログラム」と共に本使用許諾書の写しを渡してください。

    複製物の引き渡しに要する実費は請求することができます。 また、あなた独自の保証を行なう場合はそれを有償とすることができます。

  3. 次の各条件を全て満たしている限り、あなたは、 「プログラム」又はその一部分を変更して「プログラム生成物」とすることができ、 さらに、変更版や右作成物を上記第2項に従って複製又は頒布することもできます。
    1. ファイルを変更した旨とその変更日とを、変更したファイル上に明確に表示すること。
    2. 変更したか否かを問わず、凡そ「プログラム」 又はその一部分を内部に組み込んでいるか 又はそれから派生した生成物を頒布する場合には、 その全体を本使用許諾の条項に従って第三者へ無償で使用許諾すること。
    3. 変更したプログラムが実行時に通常の対話的な方法で コマンドを読むようになっているとすれば、 最も普通の方法で対話的にそのプログラムを実行する時に、 次の内容を示す文言がプリンタへ印字されるか、或いは画面に表示されること。
      • 適切な著作権表示。
      • 無保証であること(あなたが独自に保証する場合は、その旨)。
      • 頒布を受ける者も、 本使用許諾と同一の条項に従って「プログラム」を再頒布できること。
      • 頒布を受ける者が本使用許諾書の写しを参照する方法。 (例外として、「プログラム」自体は対話的であっても起動時の文言を 通常は印字しないのならば、 あなたの「プログラム生成物」はこのような文言を印字する必要はありません。)

    これらの要件は変更された作成物にも全て適用されます。 その変更版の或る部分が「プログラム」の派生物ではなく、 しかもそれ自体独立で異なる作成物だと合理的に考えられる場合、 あなたがそれらを別の作成物として頒布した時は、 本使用許諾とその条項はそれらの部分には適用されません。 しかし、それらを「プログラム生成物」の一部として頒布する場合は、 全体が本使用許諾の条項に従って頒布されなければならず、 使用許諾を受ける他の全ての者に対する許諾も プログラム全体にわたって与えられなければならず、 結果として、誰が書いたかにかかわらず、 全ての部分に本使用許諾が適用されなければなりません。

    このように、本条項の意図するところは、 完全にあなたによって書かれた作成物について、権利を要求したり、 あなたと権利関係を争うことではありません。 むしろその目的は、作成物が「プログラム生成物」 である場合にその派生物や集合物の頒布を規制することにあります。

    さらに、「プログラム」(又は「プログラム生成物」)と 「プログラム生成物」とはならない他のプログラムとを、 単に保管や頒布のために同一の媒体上にまとめて記録したとしても、 本使用許諾は他のプログラムには適用されません。

  4. あなたは、以下のうちいずれか1つを満たす限り、 上記第2項及び第3項に従って「プログラム」 (又は、上記第3項で言及している「プログラム生成物」)を オブジェクト・コード又は実行可能な形式で複製及び頒布することができます。
    1. 対応する機械読み取り可能なソース・コード一式を一緒に引き渡すこと。 その場合、そのソース・コードの引き渡しは上記第2項及び第3項に従って、 通常ソフトウェアの交換に用いられる媒体で行なわれること。
    2. 少なくとも3年間の有効期間を定め、 且つその期間内であれば対応する機械読み取り可能なソース・コード一式の複製を、 ソース頒布に関わる実費以上の対価を要求せずに提供する旨、 及びその場合には上記第2項及び第3項に従って、 通常ソフトウェアの交換に用いられる媒体で提供される旨を記載した書面を、 第三者に一緒に引き渡すこと。
    3. 対応するソース・コード頒布の申し出に際して、 あなたが得た情報を一緒に引き渡すこと。 (この選択肢は、営利を目的としない頒布であって、 且つあなたが上記の(b)項に基づいて、 オブジェクト・コード或いは実行可能形式の プログラムしか入手していない場合に限り適用される選択項目です。)

    なお、ソース・コードとは、変更作業に適した記述形式を指します。 また、実行可能形式のファイルに対応するソース・コード一式とは、 それに含まれる全モジュールに対応する全てのソース・コード、 及びあらゆる関連のインタフェース定義ファイル、 及び実行を可能にするコンパイルとインストールの制御に関する記述を指します。 特別な例外として、実行可能なファイルが動作するオペレーティング・システムの 主要な構成要素(コンパイラ、カーネルなど)と共に (ソース・コード又はバイナリのどちらかで)頒布されているものについては、 その構成要素自体が実行形式に付随していない場合に限り、 頒布されるソース・コードに含める必要はありません。

    実行可能形式またはオブジェクト・コードの頒布が、 指示された場所からの複製のためのアクセス権の賦与である場合、 同じ場所からのソース・コードの複製のための同等なアクセス権を賦与すれば、 たとえ第三者にオブジェクト・コードと共にソースの複製を強いなくとも、 ソース・コードを頒布したものとみなします。

  5. 本使用許諾が明示的に許諾している場合を除き、あなたは、 「プログラム」を複製、変更、サブライセンス、頒布することができません。 本使用許諾に従わずに「プログラム」を複製、変更、サブライセンス、 頒布しようとする行為は、それ自体が無効であり、且つ、 本使用許諾があなたに許諾している「プログラム」の権利を自動的に消滅させます。 その場合、本使用許諾に従ってあなたから複製物やその権利を得ている第三者は、 本使用許諾に完全に従っている場合に限り、 引続き有効な使用権限を持つものとします。
  6. あなたはまだ同意の印として署名していないので、 本使用許諾を受け入れる必要はありません。 しかし、あなたに「プログラム」又はその派生物を変更又は再頒布する許可を 与えるものは本使用許諾以外にはありません。 これらの行為は、あなたがもし本使用許諾を受け入れないのであれば、 法律によって禁じられます。 従って、あなたが「プログラム」(又は「プログラム生成物」)の変更又は頒布を 行えば、それ自体であなたは本使用許諾を受け入れ、且つ、 「プログラム」又はその「プログラム生成物」の複製、頒布、変更に 関するこれらの条項と条件の全てを受け入れたことを示します。
  7. あなたが「プログラム」(又はその「プログラム生成物」)を再頒布すると自動的に、 その受領者は、元の使用許諾者から、本使用許諾の条項に従って「プログラム」を 複製、頒布、変更することを内容とする使用許諾を受けたものとします。 あなたは、受領者に許諾された権利の行使について、 さらに制約を加えることはできません。 あなたには、第三者に本使用許諾の受け入れを強いる責任はありません。
  8. 裁判所の判決、又は特許侵害の申し立て、又は(特許問題に限らない) 何らかの理由の結果として、あなたに課せられた条件が本使用許諾と 相入れないものであったとしても(裁判所の命令、契約、その他によるものであれ)、 本使用許諾の条件が免除されるものではありません。 本使用許諾による責務と、その他の何らかの関連責務を同時に満たす態様で 頒布することができないならば、 あなたは「プログラム」を全く頒布してはいけません。 例えば、特許権の内容が、あなたから直接又は間接に複製を受け取った全ての人に 使用料のないプログラムの再頒布を許さないものであれば、 あなたがかかる特許上の要請と本使用許諾の両方を満足させる方法は、 「プログラム」の頒布を完全に断念することだけです。

    本条項の或る部分が何らかの特別な状況下で無効または適用不可能になった場合、 本条項のその他の残りの部分が適用されるように意図されており、また、 本条項は全体としてその他の状況に当てはまるように意図されています。

    本条項の目的は、特許やその他の財産権を侵害したり、 そのような権利に基づく主張の妥当性を争うようにあなたに 勧めることではありません。 本条項の唯一の目的は、フリー・ソフトウェアの頒布システムの完全性を守ることで、 それは公有使用許諾の実践によって履行されます。 多くの人々が、このシステムの一貫した適用を信頼して、 このシステムを通じて頒布されている幅広い範囲のソフトウェアに惜しみない貢献を してくれました。 作成者や寄贈者が他の何らかのシステムを通じてソフトウェアを 頒布したいと決めることは彼らの自由意志であり、 使用許諾を受ける者はその選択を強いることはできません。

    本条項は、本使用許諾の他の条項の意味内容が何であるかを 完全に明らかにすることを意図しています。

  9. 「プログラム」の頒布・使用が、ある国において特許又は著作権で 保護されたインタフェースのどちらかで制限される場合、 「プログラム」を本使用許諾下においた原著作権保持者は、 その国を除外する旨の明示的な頒布地域制限を加え、 それ以外の(除外されない)国に限定して頒布が 許されるようにすることができます。 そのような場合、その制限を本使用許諾の本文に あたかも書かれているかのように本使用許諾の中に組み入れられるものとします。
  10. Free Software Foundation は随時、本一般公有使用許諾の改訂版、 又は新版を公表することがあります。 そのような新しいバージョンは、 現行のバージョンと基本的に変わるところはありませんが、 新しい問題や懸案事項に対応するために細部では異なるかもしれません。

    各バージョンは、バージョン番号によって区別します。 「プログラム」中に本使用許諾のバージョン番号の指定がある場合は、 その指定されたバージョンか、又はその後にFree Software Foundationから 公表されているいずれかのバージョンから1つを選択して、 その条項と条件に従ってください。 「プログラム」中に本使用許諾のバージョン番号の指定がない場合は、 Free Software Foundation が公表したどのバージョンでも選択することができます。

  11. 「プログラム」の一部を頒布条件の異なる他のフリー・プログラムに 組み込みたい場合は、その開発者に書面で許可を求めてください。 Free Software Foundation が著作権を持っているソフトウェアについては、 Free Software Foundation へ書面を提出してください。 このような場合に対応するために我々は例外的処理をすることもありますが、 その判断基準となるのは、次の2つの目標の実現に合致するか否かという点です。 即ち、1つは我々のフリー・ソフトウェアの全ての派生物を フリーな状態に保つことであり、もう1つはソフトウェアの共有と再利用とを 広く促進させることです。
  12. 「プログラム」は無償で使用許諾されますので、適用法令の範囲内で、 「プログラム」の保証は一切ありません。 著作権者やその他の第三者は全く無保証で「そのまま」の状態で、且つ、 明示か暗黙であるかを問わず一切の保証をつけないで提供するものとします。 ここでいう保証とは、市場性や特定目的適合性についての暗黙の保証も含まれますが、 それに限定されるものではありません。 「プログラム」の品質や性能に関する全てのリスクはあなたが負うものとします。 「プログラム」に欠陥があるとわかった場合、 それに伴う一切の派生費用や修理・訂正に要する費用は全てあなたの負担とします。
  13. 適用法令の定め、又は書面による合意がある場合を除き、 著作権者や上記許諾を受けて「プログラム」の変更・再頒布を為し得る第三者は、 「プログラム」を使用したこと、 または使用できないことに起因する一切の損害について何らの責任も負いません。 著作権者や前記の第三者が、そのような損害の発生する可能性について 知らされていた場合でも同様です。 なお、ここでいう損害には通常損害、特別損害、偶発損害、間接損害が含まれます (データの消失、又はその正確さの喪失、あなたや第三者が被った損失、 他のプログラムとのインタフェースの不適合化、等も含まれますが、 これに限定されるものではありません)。

注意

英文文書(GNU General Public License)を正式文書とする。 この和文文書は弁護士の意見を採り入れて、 できるだけ正確に英文文書を翻訳したものであるが、 法律的に有効な契約書ではない。

和文文書自体の再配布に関して

いかなる媒体でも次の条件がすべて満たされている場合に限り、 本和文文書をそのまま複写し配布することを許可する。 また、あなたは第三者に対して本許可告知と同一の許可を与える場合に限り、 再配布することが許可されています。

あなたの新しいプログラムにこれらの条項を適用する方法

あなたが新しくプログラムを作成し、それを公用に供したい場合は、 プログラムをフリー・ソフトウェアにして、 全ての人々が以上の各条項に従ってこれを再頒布や変更をすることが できるようにするのが最良の方法です。

そうするためには、プログラムに以下の表示をしてください。 その場合、無保証であるということを最も効果的に伝えるために、 ソース・ファイルの冒頭にその全文を表示すれば最も安全ですが、 その他の方法で表示する場合でも、「著作権表示」と全文を読み出す為の アドレスへのポインタだけはファイル上に表示しておいてください。

プログラム名とどんな動作をするものかについての簡単な説明の行
Copyright(C) 19○○年、著作権者名

本プログラムはフリー・ソフトウェアです。
あなたは、Free Software Foundationが公表したGNU 一般公有使用許諾の
「バージョン2」或いはそれ以降の各バージョンの中からいずれかを選択し、
そのバージョンが定める条項に従って本プログラムを
再頒布または変更することができます。

本プログラムは有用とは思いますが、頒布にあたっては、
市場性及び特定目的適合性についての暗黙の保証を含めて、
いかなる保証も行ないません。
詳細についてはGNU 一般公有使用許諾書をお読みください。

あなたは、本プログラムと一緒にGNU一般公有使用許諾の写しを
受け取っているはずです。
そうでない場合は、
 Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA 2 へ手紙を書いてください。

また、ユーザが電子メイルや書信であなたと連絡をとる方法についての情報も 書き添えてください。

プログラムが対話的に動作する場合は、 対話モードで起動した時に次のような短い告知文が表示されるようにしてください。

Gnomovision バージョン69、Copyright(C)19○○年 著作権者名
Gnomovision は完全に無保証です。詳細は show w とタイプしてください。
これはフリー・ソフトウェアなので、特定の条件の下でこれを再頒布する
ことができます。詳細は show c とタイプしてください。

上記のshow wshow cは各々、 本一般公有使用許諾の関連する部分を表示するコマンドを指します。 もちろん、あなたが使うこれらのコマンドはshow wshow cといった 呼び名でなくても構いません。 さらに、それらのコマンドはあなたのプログラムに合わせる為に、 マウスでクリックしたりメニュー形式にすることもできます。

また、必要と認めた場合には、あなたの雇い主 (あなたがプログラマとして働いている場合)や在籍する学校から、 そのプログラムに対する「著作権放棄」を認めた署名入りの書面を入手してください。 ここにその文例を載せます。名前は変えてください。

Yoyodyne, Inc. は、James Hacker が開発したプログラム`Gnomovision'
(コンパイラにつなげるプログラム)についての著作権法上の全ての権利を放棄する。

Ty Coon の署名, 1 April 1989
Ty Coon, 副社長

本一般公有使用許諾は、あなたのプログラムを財産権の対象となっている 他のプログラムに組み込むことは認めていません。 あなたのプログラムがサブルーチン・ライブラリであって、 あなたがそのライブラリを財産権の対象となっている他のアプリケーションと リンクさせることによって、さらに有用なものにしようとする場合には、 本使用許諾書の代わりに、GNUライブラリ一般公有使用許諾書に従ってください。


Node:Introduction, Next:, Previous:Copying, Up:Top

はじめに

GNU Emacsテキストエディタの大部分は、 Emacs Lispと呼ばれるプログラム言語で記述してあります。 Emacs Lispで新たなコードを書いて、 それをエディタの拡張としてインストールできます。 しかし、Emacs Lispは、単なる『拡張言語』ではありません。 それ自身、れっきとしたプログラム言語です。 他のプログラム言語でできることは、Emacs Lispでできます。

Emacs Lispは、エディタで使うために設計してあるため、 ファイル、バッファ、ディスプレイ、サブプロセスなどを扱う機能に加えて、 テキストを走査し解析する特別な機能もあります。 Emacs Lispは編集機構に密に組み込まれています。 このため、編集コマンドはLispプログラムからも呼び出せる関数ですし、 カスタマイズのためのパラメータは普通のLisp変数です。

本書は、Emacs Lispを完全に記述することを目指しています。 初心者向けの入門には、Free Software Foundation刊、 Bob ChassellのAn Introduction to Emacs Lisp Programming 3 をご覧ください。 本書では、Emacsの操作を熟知しているものと仮定します。 操作に関する基本的な情報は、The GNU Emacs Manual 4 を参照してください。

おおまかにいえば、始めのほうの章では、 多くのプログラム言語に見られる機能に相当するEmacs Lispの機能を説明し、 あとのほうの章では、 Emacs Lispに特有の機能や編集に特化した機能を説明します。

本書は、2.5版です。


Node:Caveats, Next:, Up:Introduction

警告

本書は、数多くの草稿を重ねてきました。 ほぼ完璧に近いはずですが、誤りは皆無ではありません。 ふれていない話題も少なからずあります。 (大部分の個別のモードのような)副次的と捉えている話題や、 まだ執筆していない話題もあります。 完全にはこれらに対処しきれませんので、 意図的に省いたことがらもあります。 たとえば、VMSにおける利用方法に関する情報です。

本書で取り上げたことがらに関しては、本書は完璧であるべきですから、 例題や記述内容から章や節の構成順序といったことまで、 広く意見を求めています。 混乱を招くような記述や、本書でふれていないことがらを 学ぶためにソースや実験で調べる必要があるときには、 本書を改訂すべきなのでしょう。 そのときは、ぜひ、教えてください。

意見や訂正は、下記へメイルしてください。

bug-lisp-manual@gnu.org

ここに蓄積されたメイルは、誰かが改訂作業を始めるまでは、読み出しません。 改訂までに、数か月、ときには、数年経過することもあります。 ですから、返事がないと憤慨しないでください。 あなたのメイルは、そのうち処理されます。 Emacs保守グループに迅速に連絡したい場合には、 bug-gnu-emacs@gnu.orgにメイルしてください。


Node:Lisp History, Next:, Previous:Caveats, Up:Introduction

Lispの歴史

Lisp(LISt Processing language、リスト処理言語)は、 人工知能の研究向けに1950年代末にMITで初めて開発されました。 Lisp言語はとても強力なので、 エディタコマンドを記述するなどの他の目的にも理想的なのです。

長年にわたって何ダースものLispが実装されており、 それぞれが独自の特徴を有しています。 その多くは、1960年代のMITのMACプロジェクトで開発されたMaclispの 影響を受けています。 最終的には、Maclispの系統の実装者達は共同して、 Common Lispと呼ばれるLispシステムの規格を開発しました。 そうこうするうちに、MITのGerry SussmanとGuy Steeleは、 単純化してあるが非常に強力なSchemeと呼ばれるLispの方言を開発しました。

GNU EmacsはMaclispの影響を強く受けていますが、 Common Lispからの影響は少ないです。 Common Lispを知っている読者は、 Common Lispとの多くの類似点に気づかれるでしょう。 しかしながら、Common Lispの多くの機能は、 省いてあるか、単純化してあります。 これは、GNU Emacsが必要とするメモリ量を削減するためです。 ときには、劇的に単純化してあるために、 Common Lispユーザーは混乱するかもしれません。 GNU Emacs LispとCommon Lispとの相違点は、 ことあるごとに指摘するつもりです。 Common Lispを知らない読者は、何も心配することはありません。 本書は自己完結しています。

clライブラリにより、Common Lispをかなりエミュレートできます。 See Top

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


Node:Conventions, Next:, Previous:Lisp History, Up:Introduction

表記法

本節では、本書で用いる表記法を説明します。 本節を読み飛ばして、あとで参照してもかまいません。


Node:Some Terms, Next:, Up:Conventions

用語

本書では、『Lispリーダ』および『Lispプリンタ』という言葉で、 Lispオブジェクトのテキスト表現を実際のLispオブジェクトに変換する Lisp内部のルーティン群、および、逆の変換を行うルーティン群を指します。 詳しくは、See Printed Representation。 本書の読者を『プログラマ』と考えて『読者』と呼びます。 『ユーザー』とは作者自身を含めたLispプログラムを使う人のことです。

Lispコードの例は、(list 1 2 3)という形式で、 このフォントで記します。 メタな変数の名前や説明対象の関数に対する引数の名前は、 first-numberという形式で、このフォントで書きます。


Node:nil and t, Next:, Previous:Some Terms, Up:Conventions

nilt

Lispでは、シンボルnilには3つの異なる意味があります。 まず、nilという名前のシンボルです。 2つめは、真理値の(false)です。 3つめは、空リスト、つまり、要素数が0個のリストです。 変数として使った場合、nilの値はつねにnilです。

Lispリーダにとっては、()nilは同一です。 どちらも、同じオブジェクト、シンボルnilを表します。 シンボルを異なった書き方にするのは、完全に人間向けです。 ()nilをLispリーダが読み取ったあとでは、 プログラマが実際にどちらの表記を用いたかわかりません。

本書では、空リストを強調するときには()を使い、 真理値のを強調するときにはnilを使います。 これは、Lispプログラムでも使うとよい慣習です。

(cons 'foo ())                ; 空リストであることを強調する
(not nil)                     ; 真理値のであることを強調する

真理値の真を必要とする場面では、 nil以外の値は、(true)であるとみなします。 しかし、を表す望ましい書き方はtです。 を表す値が必要なとき、 適当な判断基準がない場合にはtを使います。 シンボルtの値はつねにtです。

Emacs Lispでは、niltは特別なシンボルであり、 評価するとそれ自身になります。 そのため、これらをプログラム内で定数として使うとき、 これらをクォートする必要はありません。 これらの値を変更しようとすると、エラーsetting-constantになります。 コロン(:)で始まる名前のシンボルも同様です。 See Constant Variables


Node:Evaluation Notation, Next:, Previous:nil and t, Up:Conventions

評価の表記法

評価可能なLisp式をフォーム(form、形式)と呼びます。 フォームを評価すると、Lispオブジェクトである結果を生じます。 本書の例題では、これを=>で表します。

(car '(1 2))
     => 1

これは、『(car '(1 2))を評価すると1になる』と読みます。

フォームがマクロ呼び出しの場合には、 Lispが評価すべき新たなフォームに展開します。 展開結果を==>で表します。 展開したフォームの評価結果を示す場合もあれば、 示さない場合もあります。

(third '(a b c))
     ==> (car (cdr (cdr '(a b c))))
     => c

あるフォームを説明するときに、 同一の結果を生じる別のフォームを示すことがあります。 2つのまったく等価なフォームを==で表します。

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


Node:Printing Notation, Next:, Previous:Evaluation Notation, Up:Conventions

結果表示の表記法

本書の数多くの例題は、評価するとテキストを表示します。 (*scratch*バッファのような)Lisp対話バッファで例題のコードを 実行すると、表示テキストはバッファに挿入されます。 (関数eval-regionで評価するなどの) 別の手段で例題を実行すると、表示テキストはエコー領域に表示されます。 エコー領域に表示されるテキストは、1行に切り詰められていることに 注意してください。

本書の例題では、表示場所には無関係に、 表示テキストを-|で表します。 フォームを評価した結果返される値(ここではbar)は、 後続の行に分けて書きます。

(progn (print 'foo) (print 'bar))
     -| foo
     -| bar
     => bar


Node:Error Messages, Next:, Previous:Printing Notation, Up:Conventions

エラーメッセージ

エラーを通知する例題もあります。 これは、通常、エコー領域にエラーメッセージを表示します。 エラーメッセージは、error-->で始まる行に示します。 エコー領域には、error-->は表示されないことに注意してください。

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


Node:Buffer Text Notation, Next:, Previous:Error Messages, Up:Conventions

バッファ内のテキストの表記法

バッファ内のテキストを修正する例題もあります。 このような場合、『実行前』と『実行後』のテキストを示します。 それらの例題では、バッファ名を含めたダッシュから成る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 ----------


Node:Format of Descriptions, Previous:Buffer Text Notation, Up:Conventions

記述形式

関数、変数、マクロ、コマンド、ユーザーオプション、 スペシャルフォームは、本書では統一した形式で記述します。 第1行目は、それぞれの名前と、引数があれば引数群です。 これに説明文が続き、場合によっては例題も示します。


Node:A Sample Function Description, Next:, Up:Format of Descriptions

関数の記述例

関数の記述では、まず始めに説明対象の関数名があります。 同じ行には、引数名の並びも続きます。 これらの名前は、説明文の中で引数の値を参照するために使います。

引数ならびにキーワード&optionalが現れていれば、 それ以降の引数を省略できることを示します(省略した引数の値はnil)。 関数を呼び出すときに&optionalを書いてはいけません。

キーワード&rest (このあとには1つの引数名だけが続く)は、 残りの引数が何個でもよいことを示します。 直後にある1つの引数名は、変数としての値を持ち、 その値は残りのすべての引数のリストです。 関数を呼び出すときに&restを書いてはいけません。

では、仮想的な関数fooの記述を以下に示します。

foo integer1 &optional integer2 &rest integers Function
関数fooは、integer2からinteger1を引き算し、 残りのすべての引数を減算結果に加える。 integer2を指定しないと、デフォルトでは、数19から引き算する。
(foo 1 5 3 9)
     => 16
(foo 5)
     => 14

より一般的には、つぎのとおり。

(foo w x y...)
==
(+ (- x w) y...)

integerinteger1bufferなどの)型名を名前とする引数は、 その型の値であると仮定します。 (buffersのように)型を複数形にした場合には、 しばしば、その型のオブジェクトのリストを意味します。 objectという名前の引数は、任意の型でかまいません。 (Emacsオブジェクトの型の一覧については、see Lisp Data Types)。 (new-fileなどの)その他の名前の引数は、関数の説明文の中で言及します。 複数の関数の引数に共通する特徴について、 節の始めで説明する場合もあります。

&optional&restについての詳しい説明は、 See Lambda Expressions

コマンド、マクロ、スペシャルフォームの記述も同じ形式ですが、 「関数」のかわりに 「コマンド」、「マクロ」、「スペシャルフォーム」のいずれかです。 コマンドは、対話的に呼び出せる単なる関数です。 マクロは関数とは違った方法で引数を処理します(引数を評価しない)が、 同じ方法で引数を記します。

スペシャルフォームの記述では、省略可能な引数や繰り返される引数を 示すために、より複雑な記法を使います。 というのは、引数並びを個々の引数に分離する方法が複雑だからです。 [optional-arg]は、 optional-argが省略可能であることを示します。 また、repeated-args...は、0個以上の引数を示します。 いくつかの引数をリスト構造の内側にまとめるときには、 括弧を使います。

count-loop (var [from to [inc]]) body... Special Form
この仮想的なスペシャルフォームは、 フォーム群bodyを実行してから変数varを増やすことを 反復するループを実現する。 最初は、変数の値はfromである。 以降の反復では、変数を1(あるいは、指定があればincだけ)増やす。 vartoに等しくなると、 bodyを実行せずにループから抜ける。 例を示す。
(count-loop (i 0 10)
  (prin1 i) (princ " ")
  (prin1 (aref vector i))
  (terpri))

fromtoを省略すると、 ループ開始前にvarnilを束縛し、 各反復の開始時にvarnil以外であるとループから抜け出る。

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

このスペシャルフォームでは、引数fromtoは省略できるが、 両者を同時に指定するか、同時に省略すること。 これらを指定した場合、incを指定してもよい。 これらの引数は、引数varとともにリストにまとめる。 これはbodyと区別するためであり、 bodyは残りのフォームの要素すべてを含む。


Node:A Sample Variable Description, Previous:A Sample Function Description, Up:Format of Descriptions

変数の記述例

変数(variable)は、値を保持するための名前です。 ユーザーはどんな変数でも設定できますが、 ユーザーが変更可能な特定の変数群があり、 それらをユーザーオプション(user options)と呼びます。 普通の変数もユーザーオプションも関数の記述と同じ形式で示しますが、 それらに引数はありません。

仮想的な変数electric-future-mapの記述例を示します。

electric-future-map Variable
この変数の値は、Electric Command Futureモードで使用する 完全なキーマップである。 このマップに含まれる関数は、まだ実行していないコマンドの編集を可能にする。

ユーザーオプションの記述も同じ形式ですが、 「変数」のかわりに「ユーザーオプション」です。


Node:Version Info, Next:, Previous:Conventions, Up:Introduction

版情報

これらの機構は、使用中のEmacsの版に関する情報を提供します。

emacs-version コマンド
この関数は、実行中のEmacsの版を記述した文字列を返す。 この文字列はバグの報告に含めると有益である。
(emacs-version)
  => "GNU Emacs 20.3.5 (i486-pc-linux-gnulibc1, X toolkit)
 of Sat Feb 14 1998 on psilocin.gnu.org"

対話的に呼び出すと、この関数は同じ情報をエコー領域に表示する。

emacs-build-time Variable
この変数の値は、ローカルのサイトでEmacsを構築した日時を示す。 3つの整数から成るリストであり、 current-timeと同様のもの(see Time of Day)。
emacs-build-time
     => (13623 62065 344633)

emacs-version Variable
この変数の値は、実行中のEmacsの版番号。 "20.3.1"のような文字列である。 この文字列の最後の数字は、Emacsのリリース版番号の一部ではなく、 特定のディレクトリでEmacsを構築するたびに増える。

つぎの2つの変数は、Emacs 19.23以降に存在します。

emacs-major-version Variable
Emacsのメジャー版番号を表す整数。 Emacs 20.3では、値は20。

emacs-minor-version Variable
Emacsのマイナ版番号を表す整数。 Emacs 20.3では、値は3。


Node:Acknowledgements, Previous:Version Info, Up:Introduction

謝辞

本書は、Robert Krawitz、Bil Lewis、Dan LaLiberte、 Richard M. Stallman、Chris Welty、GNUマニュアルプロジェクトのボランティア による何年にもわたる努力で執筆されました。 Computational Logic社のWarren A. Hunt, Jr.が手配した 国防省Advanced Research Projects Agency、ARPA Order 6082の援助のもと、 Robert J. Chassellは本書のレビューと編集に協力してくれました。

以下の方々が訂正を送ってくれました。 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、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、Skip Montanaro、John Gardiner Myers、Thomas A. Peterson、 Francesco Potorti、Friedrich Pukelsheim、Arnold D. Robbins、Raul Rockwell、Per Starback、Shinichirou Sugou、Kimmo Suominen、Edward Tharp、 Bill Trost、Rickard Westman、Jean White、Matthew Wilding、Carl Witty、 Dale Worley、Rusty Wright、David D. Zuhn。


Node:Lisp Data Types, Next:, Previous:Introduction, Up:Top

Lispのデータ型

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

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

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

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

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

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

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


Node:Printed Representation, Next:, Up:Lisp Data Types

表示表現と入力構文

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

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

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

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

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

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


Node:Comments, Next:, Previous:Printed Representation, Up:Lisp Data Types

コメント

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

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

コメントの体裁に関する慣習については、See Comment Tips


Node:Programming Types, Next:, Previous:Comments, Up:Lisp Data Types

プログラミング向けの型

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


Node:Integer Type, Next:, Up:Programming Types

整数型

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

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

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

より詳しくは、See Numbers


Node:Floating Point Type, Next:, Previous:Integer Type, Up:Programming Types

浮動小数点数

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

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

詳しくは、See Numbers


Node:Character Type, Next:, Previous:Floating Point Type, Up:Programming Types

文字型

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

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

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

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

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

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

?Q => 81     ?q => 113

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


Node:Symbol Type, Next:, Previous:Character Type, Up:Programming Types

シンボル型

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

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

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

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

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

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


Node:Sequence Type, Next:, Previous:Symbol Type, Up:Programming Types

シーケンス型

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

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

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

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


Node:Cons Cell Type, Next:, Previous:Sequence Type, Up:Programming Types

コンスセルとリスト型

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


Node:Dotted Pair Notation, Next:, Up:Cons Cell Type

ドット対記法

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

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

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

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

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

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

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

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

同様に、3要素のリスト(rose violet buttercup)は、 (rose . (violet . (buttercup)))に等価です。


Node:Association List Type, Previous:Dotted Pair Notation, Up:Cons Cell Type

連想リスト型

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

たとえば、

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

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

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


Node:Array Type, Next:, Previous:Cons Cell Type, Up:Programming Types

配列型

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

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

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

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

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

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


Node:String Type, Next:, Previous:Array Type, Up:Programming Types

文字列型

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

文字列を操作する関数については、See Strings and Characters


Node:Syntax for Strings, Next:, Up:String Type

文字列の構文

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

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

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


Node:Non-ASCII in Strings, Next:, Previous:Syntax for Strings, Up:String Type

文字列内の非ASCII文字

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

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

マルチバイトの16進エスケープを使うと、 文字列はマルチバイトになります。 ユニバイトの非ASCIIを文字コードで表現することもできますが、 文字コードは128(8進0200)から255(8進0377)の範囲である必要があります。 こうすると、文字列はユニバイトになります。

2種類のテキストの表現方法について詳しくは、See Text Representations


Node:Nonprinting Characters, Next:, Previous:Non-ASCII in Strings, Up:String Type

文字列内の非印字文字

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

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

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

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


Node:Text Props and Strings, Previous:Nonprinting Characters, Up:String Type

文字列内のテキスト属性

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

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

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

beg end plist

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

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

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


Node:Vector Type, Next:, Previous:String Type, Up:Programming Types

ベクトル型

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

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

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

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


Node:Char-Table Type, Next:, Previous:Vector Type, Up:Programming Types

文字テーブル型

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

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

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


Node:Bool-Vector Type, Next:, Previous:Char-Table Type, Up:Programming Types

ブールベクトル型

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

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

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


Node:Function Type, Next:, Previous:Bool-Vector Type, Up:Programming Types

関数型

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

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

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


Node:Macro Type, Next:, Previous:Function Type, Up:Programming Types

マクロ型

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

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

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


Node:Primitive Function Type, Next:, Previous:Macro Type, Up:Programming Types

基本関数型

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

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

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

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

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


Node:Byte-Code Type, Next:, Previous:Primitive Function Type, Up:Programming Types

バイトコード関数型

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

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


Node:Autoload Type, Previous:Byte-Code Type, Up:Programming Types

自動ロード型

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

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

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


Node:Editing Types, Next:, Previous:Programming Types, Up:Lisp Data Types

編集向けの型

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


Node:Buffer Type, Next:, Up:Editing Types

バッファ型

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

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

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

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

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

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

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

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


Node:Marker Type, Next:, Previous:Buffer Type, Up:Editing Types

マーカ型

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

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

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

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


Node:Window Type, Next:, Previous:Marker Type, Up:Editing Types

ウィンドウ型

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

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

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

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

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

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


Node:Frame Type, Next:, Previous:Window Type, Up:Editing Types

フレーム型

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

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

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

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


Node:Window Configuration Type, Next:, Previous:Frame Type, Up:Editing Types

ウィンドウ構成型

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

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


Node:Frame Configuration Type, Next:, Previous:Window Configuration Type, Up:Editing Types

フレーム構成型

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

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


Node:Process Type, Next:, Previous:Frame Configuration Type, Up:Editing Types

プロセス型

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

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

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

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

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


Node:Stream Type, Next:, Previous:Process Type, Up:Editing Types

ストリーム型

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

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

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

構文解析関数や表示関数を含むストリームに関連した関数の説明は、 See Read and Print


Node:Keymap Type, Next:, Previous:Stream Type, Up:Editing Types

キーマップ型

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

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


Node:Overlay Type, Previous:Keymap Type, Up:Editing Types

オーバレイ型

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

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


Node:Type Predicates, Next:, Previous:Editing Types, Up:Lisp Data Types

型述語

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

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

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

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

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

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

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

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

atom
see atom
arrayp
see arrayp
bool-vector-p
see bool-vector-p
bufferp
see bufferp
byte-code-function-p
see byte-code-function-p
case-table-p
see case-table-p
char-or-string-p
see char-or-string-p
char-table-p
see char-table-p
commandp
see commandp
consp
see consp
display-table-p
see display-table-p
floatp
see floatp
frame-configuration-p
see frame-configuration-p
frame-live-p
see frame-live-p
framep
see framep
functionp
see functionp
integer-or-marker-p
see integer-or-marker-p
integerp
see integerp
keymapp
see keymapp
listp
see listp
markerp
see markerp
wholenump
see wholenump
nlistp
see nlistp
numberp
see numberp
number-or-marker-p
see number-or-marker-p
overlayp
see overlayp
processp
see processp
sequencep
see sequencep
stringp
see stringp
subrp
see subrp
symbolp
see symbolp
syntax-table-p
see syntax-table-p
user-variable-p
see user-variable-p
vectorp
see vectorp
window-configuration-p
see window-configuration-p
window-live-p
see window-live-p
windowp
see windowp

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

type-of object Function
この関数は、objectの基本型を示すシンボルを返す。 その値は、 symbolintegerfloatstringconsvectorchar-tablebool-vectorsubrcompiled-functionmarkeroverlaywindowbufferframeprocesswindow-configurationの シンボルのうちの1つ。
(type-of 1)
     => integer
(type-of 'nil)
     => symbol
(type-of '())    ; ()nil
     => symbol
(type-of '(x))
     => cons


Node:Equality Predicates, Previous:Type Predicates, Up:Lisp Data Types

同値述語

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

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

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

(eq 'foo 'foo)
     => t

(eq 456 456)
     => t

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

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

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

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

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

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

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

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

(equal 456 456)
     => t

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

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

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

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

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

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

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

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

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


Node:Numbers, Next:, Previous:Lisp Data Types, Up:Top

GNU Emacsでは2種類の数値データを扱えます。 整数(integers)と浮動小数点数(floating point numbers)です。 整数は、-3、0、7、13、511のようなちょうどの数です。 これらの値は正確です。 浮動小数点数は、-4.5、0.0、2.71828のように小数部がある数です。 これらは指数表記で表します。 たとえば、1.5e2は150に等しいのです。 この例のe2は10の2乗を表し、それを1.5倍します。 浮動小数点数の値は厳密ではありません。 これらの精度には定まった限界があります。


Node:Integer Basics, Next:, Up:Numbers

整数の基本

整数の値の範囲は計算機に依存します。 最小の範囲は、-134217728から134217727まで(28ビット長、つまり から これより広い範囲を扱える計算機もあります。 本章の多くの例題では、整数は28長ビットであると仮定します。

Lispリーダは、 先頭に符号があってもよく、最後にピリオドがあってもよい、 数字の列として整数を読み取ります。

 1               ; 整数1
 1.              ; 整数1
+1               ; これも整数1
-1               ; 整数-1
 268435457       ; 桁溢れのため、これも整数1
 0               ; 整数0
-0               ; 整数0

整数を扱うさまざまな関数を理解するには、 特にビット演算(see Bitwise Operations)を理解するには、 数を2進表現で考えるとよいです。

28ビット長の2進表現では、10進整数5はつぎのようになります。

0000  0000 0000  0000 0000  0000 0101

(4ビットのまとまりごとに空白を1個、 8ビットのまとまりごとに空白を2個挿入して、読みやすくする。)

整数-1はつぎのようになります。

1111  1111 1111  1111 1111  1111 1111

-1は、28個の1で表現されます。 (これを2の補数(two's complement)表記と呼ぶ。)

負の数-5は、-1から4を引いて作れます。 10進数4は、2進表記では100です。 したがって、-5は、つぎのようになります。

1111  1111 1111  1111 1111  1111 1011

この実装では、28ビット長の2進整数の最大値は、 10進で134,217,727になります。 2進表記では、つぎのようになります。

0111  1111 1111  1111 1111  1111 1111

算術関数は、整数がその範囲外に出たかどうか検査しないので、 134,217,727に1を足すと、値は負の数-134,217,728になります。

(+ 1 134217727)
     => -134217728
     => 1000  0000 0000  0000 0000  0000 0000

本章で述べる多くの関数は、数の引数としてマーカを受け付けます。 (see Markers)。 そのような関数の実際の引数は数かマーカであるので、 それらの引数をしばしばnumber-or-markerという名前で書きます。 引数の値がマーカであるときには、その位置の値を使いバッファは無視します。


Node:Float Basics, Next:, Previous:Integer Basics, Up:Numbers

浮動小数点数の基本

浮動小数点数は、整数ではない数を表現するのに便利です。 浮動小数点数の正確な範囲は計算機に依存します。 使用している計算機のC言語のデータ型doubleの範囲と同じです。

浮動小数点数の入力構文は、小数点(に続けて1桁以上の小数部)または指数、 あるいは、その両方が必要です。 たとえば、1500.015e215.0e21.5e3.15e4は、同じ1500という値の 浮動小数点数を書き表す5つの方法です。 どれも、まったく等価です。 負の浮動小数点数を書くには、-1.0のようにマイナス符号を使います。

現代の計算機はIEEEの浮動小数点数規格に基づいています。 この規格では、浮動小数点数の値には正の無限大と負の無限大があります。 また、NaNすなわち『非数値』(not-a-number)と呼ばれる値の種類もあります。 算術関数は、正しい答えがないときには、このような値を返します。 たとえば、(sqrt -1.0)はNaNを返します。 実用的には、Emacs Lispでは異なるNaNの値に重要な違いはなく、 特定の場面で正確にはどのNaNの値を使うかの規則もないので、 Emacs Lispではそれらを区別しようとはしません。 浮動小数点数の入力構文はつぎのとおりです。

正の無限大
1.0e+INF
負の無限大
-1.0e+INF
非数値
0.0e+NaN

さらに、IEEEの浮動小数点数では値-0.0を普通のゼロと区別します (しかし、equal=は、これらを等しい値と扱う)。

浮動小数点数の2進指数を取り出すには(あるいは、整数の対数を予測するには)、 logbを使います。

logb number Function
この関数はnumberの2進指数を返す。 より正確には、その値はnumberの2を底とする対数を整数に切り下げたもの。
(logb 10)
     => 3
(logb 10.0e20)
     => 69


Node:Predicates on Numbers, Next:, Previous:Float Basics, Up:Numbers

数向けの型述語

本節の関数は、引数が数であるか、とか、特定の種類の数であるか検査します。 関数integerpfloatpは 引数として任意の型のLispオブジェクトを取ります (さもないと、述語の利用価値がない)。 しかし、述語zeropの引数には数が必要です。 Predicates on Markersinteger-or-marker-pnumber-or-marker-pも 参照してください。

floatp object Function
この述語は、引数が浮動小数点数かどうか調べ、 そうならばtを返し、さもなければnilを返す。

Emacs 18以前の版にはfloatpはない。

integerp object Function
この述語は、引数が整数かどうか調べ、 そうならばtを返し、さもなければnilを返す。

numberp object Function
この述語は、引数が数(整数か浮動小数点数)かどうか調べ、 そうならばtを返し、さもなければnilを返す。

wholenump object Function
(『whole-number-p』からきている名前の)述語wholenumpは、 引数が非負整数かどうか調べ、 そうならばtを返し、さもなければnilを返す。 0は非負整数として扱う。

natnumpは、wholenumpの廃れた同義語。

zerop number Function
この述語は、引数が0かどうか調べ、 そうならばtを返し、さもなければnilを返す。 引数は数であること。

つぎの2つのフォームは等価。 (zerop x) == (= x 0)


Node:Comparison of Numbers, Next:, Previous:Predicates on Numbers, Up:Numbers

数の比較

2つの数が数値的に等しいかどうか調べるには、普通、 eqではなく=を使うべきです。 数値的には等しい多くの異なる浮動小数点数が存在しえます。 それらの比較にeqを使うと、 2つの値が同一オブジェクトかどうか調べることになります。 対照的に、=はオブジェクトの数値だけを比較します。

現時点では、Emacs Lispにおいて、各整数値は一意なLispオブジェクトです。 したがって、整数に限ればeq=と等価です。 未知の値と整数を比較するためにeqを使うと便利な場面があります。 というのは、eqは任意の型の引数を受け付けるので、 eqは未知の値が数でなくてもエラーを報告しないからです。 対照的に、=は、引数が数やマーカでないと、エラーを通知します。 しかしながら、Emacsの将来の版で整数の表現方法を変更する場合に備えて、 整数を比較するときであっても、可能ならば、=を使うほうがよいでしょう。

equalで数を比較したほうが便利なこともあります。 equalは、2つの数が同じデータ型 (どちらも整数であるか、どちらも浮動小数点数である)で、 同じ値であれば、2つの数を等しいと扱います。 一方、=は、整数と浮動小数点数が等しいことを扱えます。

別のことがらもあります。 浮動小数点数演算は厳密ではないので、 2つの浮動小数点数が等しいかどうか調べるのは正しくありません。 普通、近似的に等しいことを調べるほうがよいのです。 つぎの関数はそのようにします。

(defvar fuzz-factor 1.0e-6)
(defun approx-equal (x y)
  (or (and (= x 0) (= y 0))
      (< (/ (abs (- x y))
            (max (abs x) (abs y)))
         fuzz-factor)))
Common Lispに関した注意: Common Lispでは、数の比較にはつねに=を使う必要がある。 というのは、Common Lispでは複数ワードの整数を実装しているため、 2つの異なる整数オブジェクトが同じ数値を表すことがありえる。 Emacs Lispでは、整数値の範囲が制限されているため、 任意の値の整数オブジェクトはそれぞれ1つしかない。

= number-or-marker1 number-or-marker2 Function
この関数は、引数が数値的に等しいか調べ、 そうならばtを返し、さもなければnilを返す。

/= number-or-marker1 number-or-marker2 Function
この関数は、引数が数値的に等しいか調べ、 等しくなければtを返し、等しければnilを返す。

< number-or-marker1 number-or-marker2 Function
この関数は、第1引数が第2引数より小さいか調べ、 そうならばtを返し、さもなければnilを返す。

<= number-or-marker1 number-or-marker2 Function
この関数は、第1引数が第2引数より小さいか、あるいは、等しいか調べ、 そうならばtを返し、さもなければnilを返す。

> number-or-marker1 number-or-marker2 Function
この関数は、第1引数が第2引数より大きいか調べ、 そうならばtを返し、さもなければnilを返す。

>= number-or-marker1 number-or-marker2 Function
この関数は、第1引数が第2引数より大きいか、あるいは、等しいか調べ、 そうならばtを返し、さもなければnilを返す。

max number-or-marker &rest numbers-or-markers Function
この関数は、引数の中で最大のものを返す。
(max 20)
     => 20
(max 1 2.5)
     => 2.5
(max 1 3 2.5)
     => 3

min number-or-marker &rest numbers-or-markers Function
この関数は、引数の中で最小のものを返す。
(min -4 1)
     => -4

abs number Function
この関数は、numberの絶対値を返す。


Node:Numeric Conversions, Next:, Previous:Comparison of Numbers, Up:Numbers

数の変換

整数を浮動小数点数に変換するには、 関数floatを使います。

float number Function
この関数は、浮動小数点数に変換したnumberを返す。 numberがすでに浮動小数点数ならば、 floatnumberを変更せずに返す。

浮動小数点数を整数に変換する関数は4つあります。 これらの関数は、整数も引数に取りますが、整数引数は変更せずに返します。

truncate number Function
これは、0に向けて切り捨てて整数に変換したnumberを返す。

floor number &optional divisor Function
これは、(負の無限大に向けて)切り下げて整数に変換したnumberを返す。

divisorを指定すると、切り下げるまえに numberdivisorで除算する。 これには、modに対応した除算を使い切り下げる。 divisorが0であると、結果はarith-errorになる。

ceiling number Function
これは、(正の無限大に向けて)切り上げて整数に変換したnumberを返す。

round number Function
これは、もっとも近い整数に丸めて整数に変換したnumberを返す。 2つの整数に等距離にある値を丸める場合には、 使用している計算機に依存して、ゼロに近いほうの整数を選ぶか偶数を選ぶ。


Node:Arithmetic Operations, Next:, Previous:Numeric Conversions, Up:Numbers

算術演算

Emacs Lispには、伝統的な四則演算、加算、減算、乗算、除算があります。 除算関数を補う、余りと剰余の関数もあります。 Lispの伝統でもあり、また、多用するので、1を加算したり減算する関数もあります。

これらの関数は、%を除いて、引数が1つでも浮動小数点数であると、 浮動小数点数を返します。

Emacs Lispでは、算術関数は桁溢れ(オーバフロー)を検査しないことに 注意してください。 つまり、読者の計算機に依存しますが、 (1+ 134217727)を評価すると-134217728になる場合もあります。

1+ number-or-marker Function
この関数は、number-or-marker足す1を返す。
(setq foo 4)
     => 4
(1+ foo)
     => 5

この関数はC言語の演算子++の類似ではない。 つまり、変数を増加しない。 したがって、つぎのようになる。

foo
     => 4

変数を増加するには、つぎのようにsetqを使う必要がある。

(setq foo (1+ foo))
     => 5

1- number-or-marker Function
この関数は、number-or-marker引く1を返す。

+ &rest numbers-or-markers Function
この関数は、引数をすべて加算する。 引数を指定しないと+は0を返す。
(+)
     => 0
(+ 1)
     => 1
(+ 1 2 3 4)
     => 10

- &optional number-or-marker &rest more-numbers-or-markers Function
関数-は、2つの役割、つまり、符号反転と減算を果たす。 -に1つの引数を指定すると、 その値は、引数の符号を反転したものである。 複数個の引数を指定すると、-は、 number-or-markerからmore-numbers-or-markersの1つ1つを減算する。 引数を指定しないと結果は0である。
(- 10 1 2 3 4)
     => 0
(- 10)
     => -10
(-)
     => 0

* &rest numbers-or-markers Function
この関数は、引数をすべて掛け合わせた乗算結果を返す。 引数を指定しないと*は1を返す。
(*)
     => 1
(* 1)
     => 1
(* 1 2 3 4)
     => 24

/ dividend divisor &rest divisors Function
この関数は、dividenddivisorで除し商を返す。 追加の引数divisorsを指定してあると、 dividenddivisorsの1つ1つで除す。 各引数は数かマーカである。

すべての引数が整数である場合、結果も整数となる。 つまり、結果は切り捨てになる。 ほとんどの計算機では各除算の結果は0に向けて切り捨てになるが、 負の引数を別の方法で丸める計算機もある。 これは、Lisp関数/をC言語の除算演算子で実装しているからであり、 C言語の除算演算子では計算機依存に丸めることを許しているからである。 実用上、すべての既知の計算機は標準的な方法で丸める。

整数を0で除算すると、エラーarith-errorを通知する。 (see Errors。) 浮動小数点数を0で除算すると、IEEE浮動小数点数を使う計算機では、 無限大かNaNを返す。 さもなければエラーarith-errorを通知する。

(/ 6 2)
     => 3
(/ 5 2)
     => 2
(/ 5.0 2)
     => 2.5
(/ 5 2.0)
     => 2.5
(/ 5.0 2.0)
     => 2.5
(/ 25 3 2)
     => 4
(/ -17 6)
     => -2

原理的には、(/ -17 6)が-3になる計算機もある。

% dividend divisor Function
この関数は、dividenddivisorで除したあとの整数の余りを返す。 引数は整数かマーカである必要がある。

負の引数では、余りは原理的に計算機依存である。 実用上、すべての既知の計算機は同じようにふるまう。

divisorが0であるとarith-errorになる。

(% 9 4)
     => 1
(% -9 4)
     => -1
(% 9 -4)
     => 1
(% -9 -4)
     => -1

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

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

は、つねにdividendに等しい。

mod dividend divisor Function
この関数は、dividenddivisorによる剰余を返す。 いいかえれば、dividenddivisorで除した余りを返す。 ただし、その符号はdivisorと同じ。 引数は数かマーカである必要がある。

%と違い、 modは負の引数に対しても厳密に定義された結果を返す。 浮動小数点の引数も許す。 商を(負の無限大に向けて)切り下げて整数にし、 その商を用いて余りを計算する。

divisorが0であるとarith-errorになる。

(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に等しい。 ただし、どちらかの引数が浮動小数点数の場合には、 丸め誤差の範囲内で等しい。 floorについては、Numeric Conversionsを参照。


Node:Rounding Operations, Next:, Previous:Arithmetic Operations, Up:Numbers

丸め演算

関数、ffloorfceilingfroundftruncateは、 浮動小数点数引数を受け取り、その値に近い整数を値とする浮動小数点数を返します。 ffloorは、もっとも近いより小さな整数を返します。 fceilingは、もっとも近いより大きな整数を返します。 ftruncateは、0に向けて切り捨てたもっとも近い整数を返します。 froundは、もっとも近い整数を返します。

ffloor float Function
この関数は、floatをこれより小さな整数値に切り下げ、 その値を浮動小数点数として返す。

fceiling float Function
この関数は、floatをこれより大きな整数値に切り上げ、 その値を浮動小数点数として返す。

ftruncate float Function
この関数は、floatを0に向けて整数値に切り捨て、 その値を浮動小数点数として返す。

fround float Function
この関数は、floatをもっとも近い整数値に丸め、 その値を浮動小数点数として返す。


Node:Bitwise Operations, Next:, Previous:Rounding Operations, Up:Numbers

整数のビット演算

計算機内部では、整数は2進数、つまり、 ビット(bit、各桁は0か1)列で表現されます。 ビット演算は、そのようなビット列の各ビットごとに作用します。 たとえば、シフト(shifting)は、ビット列を全体として左や右に 1桁以上移動して、その『移動後の』パターンを結果とします。

Emacs Lispにおけるビット演算は整数に限ります。

lsh integer1 count Function
論理シフト(logical shift)の略からきているlshは、 integer1のビット列をcount桁左へ、 あるいは、countが負ならば右へずらし、空いたビットには0を詰める。 countが負であれば、lshは最左(最上位)ビットに0を詰め、 integer1が負であっても結果は正になる。 これと対照的なのが下のash

lshの例を2つ示す。 ビットパターンを1桁左へずらす。 ビットパターンの上位ビットはすべて0なので下位8ビットだけを示す。

(lsh 5 1)
     => 10
;; 10進数5は、 10進数10になる
00000101 => 00001010

(lsh 7 1)
     => 14
;; 10進数7は、10進数14になる
00000111 => 00001110

例からわかるように、ビットパターンを1桁左へずらすと、 もとの数値の2倍の数になる。

ビットパターンを2桁左へずらすと、(8ビット長の2進数では)つぎのようになる。

(lsh 3 2)
     => 12
;; 10進数3は、10進数12になる
00000011 => 00001100

一方、右へずらすとつぎのようになる。

(lsh 6 -1)
     => 3
;; 10進数6は、10進数3になる
00000110 => 00000011

(lsh 5 -1)
     => 2
;; 10進数5は、10進数2になる
00000101 => 00000010

例からわかるように、ビットパターンを1桁右へずらすと、 正の整数の数を2で除して切り下げる。

Emacs Lispのすべての算術関数と同様に、 関数lshは桁溢れ(オーバフロー)を検査しないので、 左へずらすと上位ビットを捨てさり数の符号を変えてしまうことがある。 たとえば、28ビット長の計算機では、 134,217,727を左へずらすと-2になる。

(lsh 134217727 1)          ; 左シフト
     => -2

28ビット長の実装の2進数では、引数はつぎのようになっている。

;; 10進数134,217,727
0111  1111 1111  1111 1111  1111 1111

これを左へずらすと、つぎのようになる

;; 10進数-2
1111  1111 1111  1111 1111  1111 1110

ash integer1 count Function
ash算術シフト(arithmetic shift))は、 integer1のビットをcount桁左へ、あるいは、 countが負ならば右へずらす。

ashlshと同じ結果になるが、 integer1countの両者が負の場合を除く。 この場合、ashは左の空いたビットには1を入れるが、 lshはそのようなビットには0を入れる。

したがって、ashでビットパターンを1桁右へずらすとつぎのようになる。

(ash -6 -1) => -3
;; 10進数-6は、10進数-3になる
1111  1111 1111  1111 1111  1111 1010
     =>
1111  1111 1111  1111 1111  1111 1101

対照的に、lshでビットパターンを1桁右へずらすとつぎのようになる。

(lsh -6 -1) => 134217725
;; 10進数-6は、10進数134,217,725になる
1111  1111 1111  1111 1111  1111 1010
     =>
0111  1111 1111  1111 1111  1111 1101

他の例を以下にしめす。

                   ;               28ビット2進値

(lsh 5 2)          ;   5  =  0000  0000 0000  0000 0000  0000 0101
     => 20         ;      =  0000  0000 0000  0000 0000  0001 0100
(ash 5 2)
     => 20
(lsh -5 2)         ;  -5  =  1111  1111 1111  1111 1111  1111 1011
     => -20        ;      =  1111  1111 1111  1111 1111  1110 1100
(ash -5 2)
     => -20
(lsh 5 -2)         ;   5  =  0000  0000 0000  0000 0000  0000 0101
     => 1          ;      =  0000  0000 0000  0000 0000  0000 0001
(ash 5 -2)
     => 1
(lsh -5 -2)        ;  -5  =  1111  1111 1111  1111 1111  1111 1011
     => 4194302    ;      =  0011  1111 1111  1111 1111  1111 1110
(ash -5 -2)        ;  -5  =  1111  1111 1111  1111 1111  1111 1011
     => -2         ;      =  1111  1111 1111  1111 1111  1111 1110

logand &rest ints-or-markers Function
この関数は引数の『論理積』を返す。 つまり、すべての引数のn番目のビットが1である場合に限り、 結果のn番目のビットも1になる。

たとえば、4ビットの2進数で考えると、 13と12の『論理積』は12になる。 つまり、1101に1100を組み合わせると1100になる。 どちらの2進数も最左の2ビットは1なので、戻り値の最左の2ビットも1になる。 しかし、最右の2ビットは、一方の引数ではそれぞれが0なので、 戻り値の最右の2ビットも0になる。

したがって、つぎのとおり。

(logand 13 12)
     => 12

logandにまったく引数を指定しないと値-1を返す。 この数は2進表現ではすべて1だけなので、 logandの恒等元である。 logandに引数を1つだけ指定するとその引数を返す。

                   ;                28ビット2進値

(logand 14 13)     ; 14  =  0000  0000 0000  0000 0000  0000 1110
                   ; 13  =  0000  0000 0000  0000 0000  0000 1101
     => 12         ; 12  =  0000  0000 0000  0000 0000  0000 1100

(logand 14 13 4)   ; 14  =  0000  0000 0000  0000 0000  0000 1110
                   ; 13  =  0000  0000 0000  0000 0000  0000 1101
                   ;  4  =  0000  0000 0000  0000 0000  0000 0100
     => 4          ;  4  =  0000  0000 0000  0000 0000  0000 0100

(logand)
     => -1         ; -1  =  1111  1111 1111  1111 1111  1111 1111

logior &rest ints-or-markers Function
この関数は引数の『論理和』を返す。 つまり、少なくともどれか1つの引数のn番目のビットが1である場合に限り、 結果のn番目のビットも1になる。 引数を指定しないと0を返すが、これはこの演算の恒等元である。 logiorに引数を1つだけ指定するとその引数を返す。
                   ;                28ビット2進値

(logior 12 5)      ; 12  =  0000  0000 0000  0000 0000  0000 1100
                   ;  5  =  0000  0000 0000  0000 0000  0000 0101
     => 13         ; 13  =  0000  0000 0000  0000 0000  0000 1101

(logior 12 5 7)    ; 12  =  0000  0000 0000  0000 0000  0000 1100
                   ;  5  =  0000  0000 0000  0000 0000  0000 0101
                   ;  7  =  0000  0000 0000  0000 0000  0000 0111
     => 15         ; 15  =  0000  0000 0000  0000 0000  0000 1111

logxor &rest ints-or-markers Function
この関数は引数の『排他的論理和』を返す。 つまり、引数のn番目のビットが1であるものが奇数個の場合に限り、 結果のn番目のビットも1になる。 引数を指定しないと0を返すが、これはこの演算の恒等元である。 logxorに引数を1つだけ指定するとその引数を返す。
                   ;               28ビット2進値

(logxor 12 5)      ; 12  =  0000  0000 0000  0000 0000  0000 1100
                   ;  5  =  0000  0000 0000  0000 0000  0000 0101
     => 9          ;  9  =  0000  0000 0000  0000 0000  0000 1001

(logxor 12 5 7)    ; 12  =  0000  0000 0000  0000 0000  0000 1100
                   ;  5  =  0000  0000 0000  0000 0000  0000 0101
                   ;  7  =  0000  0000 0000  0000 0000  0000 0111
     => 14         ; 14  =  0000  0000 0000  0000 0000  0000 1110

lognot integer Function
この関数は引数の論理的な補数を返す。 つまり、integern番目のビットが0である場合に限り、 結果のn番目のビットは1になる。
(lognot 5)
     => -6
;;  5  =  0000  0000 0000  0000 0000  0000 0101
;; becomes
;; -6  =  1111  1111 1111  1111 1111  1111 1010


Node:Math Functions, Next:, Previous:Bitwise Operations, Up:Numbers

標準数学関数

これらの数学関数は浮動小数点数に加えて整数も引数として受け付けます。

sin arg Function
cos arg Function
tan arg Function
これらは普通の三角関数であり、引数は弧度法で表す。

asin arg Function
(asin arg)の値は-pi/2からpi/2までの数であり、 その正弦(sin)はargに等しい。 しかし、argが([-1, 1]の)範囲を越えていると結果はNaN。

acos arg Function
(acos arg)の値は0からpiまでの数であり、 その余弦(cos)はargに等しい。 しかし、argが([-1, 1]の)範囲を越えていると結果はNaN。

atan arg Function
(atan arg)の値は-pi/2からpi/2までの数であり、 その正接(tan)はargに等しい。

exp arg Function
これは指数関数であり、 のarg乗を返す。 は数学の基本定数であり、自然対数の底とも呼ぶ。

log arg &optional base Function
この関数はargbaseを底とする対数を返す。 baseを指定しなければ、底として を使う。 argが負であると結果はNaN。

log10 arg Function
この関数はargの10を底とする対数を返す。 argが負であると結果はNaN。 少なくとも誤差を考慮すれば、 (log10 x) == (log x 10)

expt x y Function
この関数はxy乗を返す。 どちらの引数も整数でありyが正ならば、結果は整数。 この場合、結果は整数値の可能な範囲に切り詰められる。

sqrt arg Function
この関数はargの平方根を返す。 argが負であると値はNaN。


Node:Random Numbers, Previous:Math Functions, Up:Numbers

乱数

決定論的な計算機プログラムは真の乱数を発生できません。 しかし、ほとんどの目的には疑似乱数(pseudo-random numbers)で十分です。 一連の疑似乱数を決定論的な方法で生成します。 それらの数は真の乱数ではありませんが、 乱数列のある種の性質に似た性質があります。 たとえば、疑似乱数列でもすべての可能な数がしばしば等しく生起します。

Emacsでは、疑似乱数は『種』となる数から生成します。 指定した任意の種から始めても、関数randomは同じ数の列を生成します。 Emacsはつねに同じ種の値で計算し始めるため、 それぞれのEmacsの実行でもrandomは実際には同じ数の列を生成します。 たとえば、あるオペレーティングシステムで、 Emacs開始直後にrandomを呼ぶとつねに-1457731を返し、 つぎに呼ぶとつねに-7692030を返します。 このような再現性はデバッグには有利です。

予測不可能な乱数が必要ならば(random t)を実行します。 これは、現在時刻とEmacsプロセスのID番号に基づいて、 新たな種の値を選びます。

random &optional limit Function
この関数は疑似乱数の整数を返す。 繰り返し呼び出すと一連の疑似乱数の整数を返す。

limitが正整数ならば、非負でlimit未満になるように値を選ぶ。

limittならば、 現在時刻とEmacsプロセスのID番号に基づいて、 新たな種の値を選ぶことを意味する。

randomの結果は、Lispにおいて表現可能な任意の整数になる計算機もある。 他の計算機では、結果はある最大値と(負数)最小値のあいだにある。


Node:Strings and Characters, Next:, Previous:Numbers, Up:Top

文字列と文字

Emacs Lispの文字列は文字の順序列を保持している配列です。 文字列は、シンボル、バッファ、ファイルのそれぞれの名前として、 ユーザーへメッセージを送るため、 バッファ間でコピーするテキストを保持するため、 その他さまざまな目的に使われます。 文字列はとても重要なので、 Emacs Lispには文字列を操作する関数が数多くあります。 Emacs Lispのプログラムでは、個々の文字よりも文字列を多用します。

キーボード文字イベントを表す文字列に関する特別な配慮については、 See Strings of Events


Node:String Basics, Next:, Up:Strings and Characters

文字列と文字の基本

Emacs Lispの文字列は文字の順序列を保持している配列です。 Emacs Lispでは文字を整数で表現します。 整数が文字であるかどうかは、その使われ方からしか判断できません。 したがって、文字列は、実際には、整数群を保持しているのです。

(任意の配列と同様に)文字列の長さは固定されていて、 文字列をいったん作成すると変更できません。 Lispの文字列は特別な文字コードで終端されるのではありません。 (対照的に、C言語の文字列はASCIIコード0で終端される。)

文字列は配列ですからシーケンスでもあり、 一般の配列関数やシーケンス関数で文字列を操作できます。 (see Sequences Arrays Vectors。) たとえば、関数arefaset(see Array Functions)を 用いて、文字列内の個々の文字を参照したり変更できます。

Emacs文字列(およびバッファ)内の非ASCII文字のテキスト表現は 2種類あります。 ユニバイトとマルチバイトです(see Text Representations)。 ASCII文字は、文字列内ではつねに1バイトを占めます。 実際、すべてがASCII文字である文字列では、2つの表現に違いはありません。 ほとんどのLispプログラムでは、 読者はこれらの2つの表現を考慮する必要はないでしょう。

キー列を文字列として表現することがあります。 文字列がキー列を表す場合、128から255の範囲にある文字列の要素は、 その範囲の文字コードとしてではなく、 (非常に大きな整数になる)メタ文字を表現します。

文字列は、ハイパー、スーパー、アルトの修飾子を持つ文字を保持できません。 文字列はASCIIコントロール文字を保持できますが、 それ以外のコントロール文字を保持できません。 文字列では、ASCIIコントロール文字の大文字小文字を区別できません。 キー列などのそのような文字をシーケンスに収めるには、 文字列のかわりにベクトルを使う必要があります。 キーボード入力文字に対するメタなどの修飾子の表現については、 See Character Type

文字列は正規表現を保持するのにも便利です。 文字列に対して正規表現の一致を取ることもできます(see Regexp Search)。 関数match-string(see Simple Match Data)と replace-match(see Replacing Match)は、 正規表現の一致に基づいて文字列を分解したり変更するのに便利です。

バッファと同様に、文字列は、 文字そのものに加えて文字列内の文字に対するテキスト属性を保持できます。 See Text Properties。 文字列からバッファや他の文字列へテキストをコピーするすべてのLisp基本関数は、 コピーする文字の属性もコピーします。

文字列を表示したりバッファへコピーする関数については、See Text。 文字と文字列の構文については、Character TypeとSee String Type。 テキスト表現を変換したり、文字コードを符号化/復号化する関数については、 See Non-ASCII Characters


Node:Predicates for Strings, Next:, Previous:String Basics, Up:Strings and Characters

文字列向けの述語

一般のシーケンスや配列に対する述語について詳しくは、 Sequences Arrays VectorsとSee Arrays

stringp object Function
この関数は、objectが文字列ならばtを返し、 さもなければnilを返す。

char-or-string-p object Function
この関数は、objectが文字列か文字(つまり、整数)ならば tを返し、さもなければnilを返す。


Node:Creating Strings, Next:, Previous:Predicates for Strings, Up:Strings and Characters

文字列の作成

以下の関数は、新たに文字列を作成したり、 文字列を連結したり分解して文字列を作成します。

make-string count character Function
この関数は、文字charactercount回繰り返して作成した文字列を返す。 countが負であるとエラーを通知する。
(make-string 5 ?x)
     => "xxxxx"
(make-string 0 ?x)
     => ""

この関数に対比するものに、 char-to-string(see String Conversion)、 make-vector(see Vectors)、 make-list(see Building Lists)などがある。

string &rest characters Function
これは、複数個の文字群charactersが入った文字列を返す。
(string ?a ?b ?c)
     => "abc"

substring string start &optional end Function
この関数は、stringstartから end(の直前)までの範囲にある文字から成る新たな文字列を返す。 先頭の文字を0で添字付けする。
(substring "abcdefg" 0 3)
     => "abc"

ここで、aの添字は0、bの添字は1、cの添字は2である。 したがって、文字列"abcdefg"から3文字abcをコピーする。 添字3はコピーする部分文字列の境界の文字位置を表す。 添字が3である文字は、実際には文字列内の4番目の文字である。

負の数は文字列の末尾から数える。 したがって、-1は文字列の最後の文字の添字である。 たとえば、

(substring "abcdefg" -3 -1)
     => "ef"

この例では、eの添字は-3、fの添字は-2、 gの添字は-1である。 したがって、efを含むがgは含まない。

添字にnilを使うと、文字列の長さを意味する。 したがって、つぎのようになる。

(substring "abcdefg" -3 nil)
     => "efg"

引数endを省略することは、nilを指定することと等価である。 そのため、(substring string 0)は、 string全体をコピーしたものを返す。

(substring "abcdefg" 0)
     => "abcdefg"

しかし、このような目的にはcopy-sequenceを勧める (see Sequence Functions)。

stringからコピーした文字にテキスト属性があれば、 新たな文字列にもそのテキスト属性をコピーする。 see Text Properties

substringは第1引数としてベクトルも受け付ける。 たとえば、つぎのとおり。

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

startendが整数でもnilでもないと、 エラーwrong-type-argumentを通知する。 startendよりうしろの文字を指していたり、 いずれかの整数がstringの範囲外であると エラーargs-out-of-rangeを通知する。

この関数と対照的なのがbuffer-substring (see Buffer Contents)であり、 カレントバッファ内のテキストの一部を収めた文字列を返す。 文字列の先頭は0で添字付けするが、バッファの先頭は1で添字付けする。

concat &rest sequences Function
この関数は、渡した引数の文字から成る (テキスト属性があればそれも含めて)新たな文字列を返す。 引数は、文字列、数のリスト、数のベクトルである。 引数自身は変更しない。 concatに引数を指定しないと空文字列を返す。
(concat "abc" "-def")
     => "abc-def"
(concat "abc" (list 120 121) [122])
     => "abcxyz"
;; nilは空シーケンス
(concat "abc" nil "-def")
     => "abc-def"
(concat "The " "quick brown " "fox.")
     => "The quick brown fox."
(concat)
     => ""

関数concatは、 既存の文字列とeqではない新たな文字列をつねに作り出す。

引数が(整数のシーケンスではなく)整数であると、 その整数の表示表現を構成する文字列に変換する。 この機能を使わないでほしい。 削除する予定である。 読者がこの機能を使っていたら、今すぐプログラムを直すこと! 整数をこのような10進数に変換する正しい方法は、 format(see Formatting Strings)や number-to-string(see String Conversion)を使うことである。

(concat 137)
     => "137"
(concat 54 321)
     => "54321"

他の連結関数については、 Mapping FunctionsmapconcatVectorsvconcatBuilding Listsappendを参照。

split-string string separators Function
stringを正規表現separatorsの一致箇所で区切って 部分文字列に分解する。 separatorsに一致するそれぞれの部分が分割箇所を定義する。 分割箇所のあいだにある部分文字列をリストにまとめ、これを値とする。 separatorsnilである(つまり、省略する)と、 デフォルトは"[ \f\t\n\r\v]+"である。

たとえば、つぎのようになる。

(split-string "Soup is good food" "o")
=> ("S" "up is g" "" "d f" "" "d")
(split-string "Soup is good food" "o+")
=> ("S" "up is g" "d f" "d")

文字列の先頭や末尾で一致した場合には、 リストの先頭や末尾に空文字列は現れない。

(split-string "out to moo" "o+")
=> ("ut t" " m")

空の一致箇所は、それらが連続していない限り分割点になる。

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


Node:Modifying Strings, Next:, Previous:Creating Strings, Up:Strings and Characters

文字列の変更

既存の文字列の内容を変更するもっとも基本的な方法は、 aset(see Array Functions)を使うことです。 (aset string idx char)は、 stringの添字idx位置にcharを格納します。 各文字は1バイト以上を占めます。 charが必要とするバイト数が指定した添字位置の文字が占めるバイト数と 異なる場合には、asetはエラーを通知します。

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

store-substring string idx obj Function
この関数は、文字列stringの添字idx位置から始まる部分にobjを 格納することで、文字列stringの内容の一部分を変更する。 引数objは文字であるか(より小さな)文字列。

既存の文字列の長さを変更することは不可能なので、 新たな文字に必要なバイト数がstringの当該箇所の文字のバイト数と 異なるなどして、 objstringの実際の長さに収まらないときにはエラーである。


Node:Text Comparison, Next:, Previous:Modifying Strings, Up:Strings and Characters

文字と文字列の比較

char-equal character1 character2 Function
この関数は、引数が同じ文字を表していればtを返し、 さもなければnilを返す。 case-fold-searchnil以外であると、 この関数は大文字小文字の違いを区別しない。
(char-equal ?x ?x)
     => t
(let ((case-fold-search nil))
  (char-equal ?x ?X))
     => nil

string= string1 string2 Function
この関数は、2つの文字列の各文字が正確に一致すればtを返す。 大文字小文字を区別する。
(string= "abc" "abc")
     => t
(string= "abc" "ABC")
     => nil
(string= "ab" "ABC")
     => nil

関数string=は2つの文字列のテキスト属性を無視する。 equal(see Equality Predicates)が2つの文字列を比較する際には、 string=を使う。

文字列に非ASCII文字が含まれ、 一方がユニバイトであり他方がマルチバイトである場合、 それらが等しいことはない。 see Text Representations

string-equal string1 string2 Function
string-equalstring=の別名。

string< string1 string2 Function
この関数は2つの文字列を1文字ずつ比較する。 まず、文字列を走査し、対応する文字同士の対で一致しないものを探す。 そのような対の文字の小さいほうがstring1の文字であるならば、 string1が小さく、この関数はtを返す。 文字の小さいほうがstring2の文字であるならば、 string1が大きく、この関数はnilを返す。 2つの文字列が完全に一致する場合、値はnilである。

文字の対は、それらの文字コードで比較する。 ASCII文字集合では、小文字は大文字より大きな数値であり、 数字文字や多くの句読点文字は大文字より小さな数値であることに注意。 ASCII文字はどんな非ASCII文字よりも小さい。 ユニバイト非ASCII文字はマルチバイト非ASCII文字よりもつねに小さい。 (see Text Representations)。

(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

string-lessp string1 string2 Function
string-lesspstring<の別名。

compare-strings string1 start1 end1 string2 start2 end2 &optional ignore-case Function
この関数は、string1の指定部分とstring2の指定部分を比較する。 string1の指定部分は、 添字start1位置から始まり添字end1位置までである (デフォルトは文字列の末尾)。 string2の指定部分は、 添字start2位置から始まり添字end2位置までである (デフォルトは文字列の末尾)。

どちらの文字列も比較のためにマルチバイトに変換するので (see Text Representations)、 ユニバイト文字列とマルチバイトが等しくなる場合もある。 ignore-casenilでなければ、大文字小文字を区別しないので、 大文字は小文字に等しくなる

2つの文字列の指定部分が一致すれば、値はt。 さもなければ、値は何文字目までが一致してどちらの文字列が小さいかを示す。 その絶対値は、2つの文字列の始めから一致した文字の個数に1を加えたもの。 string1(の指定部分)が小さいならば符号は負になる。

assoc-ignore-case key alist Function
この関数は、assocと同様に動作するが、 keyは文字列である必要があり、 compare-stringsを用いて比較する点が異なる。 大文字小文字を区別しないで比較する。

assoc-ignore-representation key alist Function
この関数は、assocと同様に動作するが、 keyは文字列である必要があり、 compare-stringsを用いて比較する点が異なる。 大文字小文字を区別して比較する。

バッファ内のテキストを比較する Comparing Textcompare-buffer-substringsも参照してください。 文字列に対して正規表現の一致を取る関数string-matchは、 ある種の文字列比較に使えます。 See Regexp Search


Node:String Conversion, Next:, Previous:Text Comparison, Up:Strings and Characters

文字と文字列の変換

本節では、文字や文字列と整数のあいだの変換関数について説明します。 formatprin1-to-string(see Output Functions)は、 Lispオブジェクトを文字列に変換するために使えます。 read-from-string(see Input Functions)は、 Lispオブジェクトの文字列表現をオブジェクトに『変換』できます。 関数string-make-multibytestring-make-unibyteは、 文字列のテキスト表現を変換します(see Converting Representations)。

テキスト文字と一般の入力イベントのテキスト表現を生成する関数 (single-key-descriptiontext-char-description)については、 See Documentation。 これらの関数は、主に、ヘルプメッセージの作成に使います。

char-to-string character Function
この関数は、1つの文字characterだけを含む新たな文字列を返す。 関数stringのほうがより汎用であるので、 この関数はほぼ廃れている。 see Creating Strings

string-to-char string Function
この関数は、stringの先頭文字を返す。 文字列が空であると関数は0を返す。 文字列stringの先頭文字が、ASCIIコードが0のナル文字であるときも、 値は0である。
(string-to-char "ABC")
     => 65
(string-to-char "xyz")
     => 120
(string-to-char "")
     => 0
(string-to-char "\000")
     => 0

この関数は、存続させるほど有用でなければ、将来、取り除くかもしれない。

number-to-string number Function
この関数は、numberの表示表現である文字列を返す。 numberは整数か浮動小数点数。 引数が負であれば値の文字列は符号で始まる。
(number-to-string 256)
     => "256"
(number-to-string -23)
     => "-23"
(number-to-string -23.5)
     => "-23.5"

int-to-stringは、この関数のほぼ廃れている別名。 Formatting Stringsformatも参照。

string-to-number string &optional base Function
この関数は、string内の文字群が表す数値を返す。 basenil以外ならば、これを基数として整数に変換する。 basenilならば10を基数とする。 浮動小数点数の変換はつねに10を基数とする。 浮動小数点数に対しては別の基数を実装していない。 作業量も多くそのわりには有用とも思えないからである。

解析するとき、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-intはこの関数の廃れた別名。

文字列へ/から変換するその他の関数を以下にあげておきます。

concat
concatは、ベクトルやリストを文字列へ変換する。 see Creating Strings
vconcat
vconcatは、文字列をベクトルへ変換する。 see Vector Functions
append
appendは、文字列をリストへ変換する。 see Building Lists


Node:Formatting Strings, Next:, Previous:String Conversion, Up:Strings and Characters

文字列の書式付け

書式付け(formatting)とは、 定数文字列内のさまざま部分を計算値で置き換えた文字列を作ることです。 この文字列は、文字列自体に加えて、 他の値をどのように表示するかも制御します。 この文字列を書式付け文字列(format string)と呼びます。

書式付けは、表示するメッセージを計算する場合に便利です。 実際、関数messageと関数errorには、 ここで説明するのと同じ書式付け機能があります。 それらとformatとの違いは、 書式付けした結果をどのように利用するかです。

format string &rest objects Function
この関数は、stringをコピーし、 コピー内の書式付け指定を対応するobjectsの表現で置き換えた 新たな文字列を返す。 引数objectsは書式付けすべき計算値である。

書式付け指定は%で始まる文字の列です。 したがって、string内に%dがあると、 関数formatはそれを書式付けすべき値の1つ (引数objectsの1つ)の表示表現で置き換えます。 たとえば、つぎのとおりです。

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

stringに2個以上の書式付け指定がある場合、 書式付け指定はobjectsの後続の値に対応します。 つまり、stringの最初の書式付け指定は最初の値を使い、 2番目の書式付け指定は2番目の値を使い、といった具合です。 (値が対応しない)余計な書式付け指定は、 予測不可能なふるまいを引き起こします。 余計な値は無視します。

特定の書式付け指定は、特定の型の値を必要とします。 要求に適合しない値を読者が指定するとエラーを通知します。

有効な書式付け指定をつぎに示します。

%s
書式付け指定をオブジェクトのクォートしない (つまり、prin1ではなくprincを用いる。see Output Functions) 表示表現で置き換える。 したがって、文字列は"文字なしでその内容を表示し、 シンボルは\文字なしで表示する。

対応するオブジェクトがなければ空文字列を使う。

%S
書式付け指定をオブジェクトのクォートした (つまり、prin1を用いる。see Output Functions) 表示表現で置き換える。 したがって、文字列は"文字で囲んで表示し、 シンボルは特別な文字のまえには\文字を付けて表示する。

対応するオブジェクトがなければ空文字列を使う。

%o
書式付け指定を整数の基数8の表示表現で置き換える。
%d
書式付け指定を整数の基数10の表示表現で置き換える。
%x
書式付け指定を整数の基数16の表示表現で置き換える。
%c
書式付け指定を指定値の文字で置き換える。
%e
書式付け指定を浮動小数点数の指数表記で置き換える。
%f
書式付け指定を浮動小数点数の小数点表記で置き換える。
%g
書式付け指定を浮動小数点数の指数表記か小数点表記のどちらか短いほうで 置き換える。
%%
文字列に1個の%を入れる。 この書式付け指定は、値を使わない点で特別である。 たとえば、(format "%% %d" 30)"% 30"を返す。

上記以外の書式付け文字は、エラーInvalid format operationになります。

例をいくつか示します。

(format "The name of this buffer is %s." (buffer-name))
     => "The name of this buffer is strings.texi."

(format "The buffer object prints as %s." (current-buffer))
     => "The buffer object prints as strings.texi."

(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 "%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は、どんな幅を指定しても、 オブジェクトの表示表現を切り詰めることはありません。 つまり、情報を失うことなく、数前置子を使って最小の桁幅を指定できます。

つぎの3つの例において、%7sは最小幅7を指定します。 最初の例では、%7sに置き換わる文字列は3文字ですから、 パディングとして空白4個を挿入します。 2番目の例では、文字列"specification"は13文字幅ですが切り詰めません。 3番目の例では、右側にパディングします。

(format "The word `%7s' actually has %d letters in it."
        "foo" (length "foo"))
     => "The word `    foo' actually has 3 letters in it."

(format "The word `%7s' actually has %d letters in it."
        "specification" (length "specification"))
     => "The word `specification' actually has 13 letters in it."

(format "The word `%-7s' actually has %d letters in it."
        "foo" (length "foo"))
     => "The word `foo    ' actually has 3 letters in it."


Node:Case Conversion, Next:, Previous:Formatting Strings, Up:Strings and Characters

Lispの大文字小文字変換

大文字小文字変換関数は、1文字や文字列内の大文字小文字を変更します。 関数は、通常、アルファベット文字 (非ASCII文字のアルファベットに加えて、 AからZaからz)だけを変換します。 それ以外の文字は変わりません。 (大文字小文字テーブルを指定して異なる大文字小文字変換を指定できる。 see Case Tables

これらの関数は、引数として渡した文字列は変更しません。

以下の例では、文字Xxを使います。 ASCIIコードは、それぞれ、88と120です。

downcase string-or-char Function
この関数は、文字や文字列を小文字に変換する。

downcaseの引数が文字列であると、 この関数は、引数の各文字の大文字を小文字に変換した新たな文字列を作成する。 downcaseの引数が文字であると、 downcaseは対応する小文字を返す。 この値は整数である。 もとの文字が小文字であったりアルファベット文字でなければ、 値はもとの文字に等しい。

(downcase "The cat in the hat")
     => "the cat in the hat"

(downcase ?X)
     => 120

upcase string-or-char Function
この関数は、文字や文字列を大文字に変換する。

upcaseの引数が文字列であると、 この関数は、引数の各文字の小文字を大文字に変換した新たな文字列を作成する。

upcaseの引数が文字であると、 upcaseは対応する大文字を返す。 この値は整数である。 もとの文字が大文字であったりアルファベット文字でなければ、 値はもとの文字に等しい。

(upcase "The cat in the hat")
     => "THE CAT IN THE HAT"

(upcase ?x)
     => 88

capitalize string-or-char Function
この関数は、文字列や文字をキャピタライズ(先頭文字だけを大文字に)する。 string-or-charが文字列ならば、 この関数は、string-or-charのコピーの各単語をキャピタライズしたものを 内容とする新たな文字列を作成して返す。 つまり、各単語の先頭文字だけを大文字にして残りを小文字にする。

単語の定義は、現在の構文テーブル(See Syntax Class Table)において 単語構成文字に分類された文字が連続した列である。

capitalizeの引数が文字の場合には、 capitalizeupcaseの結果と同じである。

(capitalize "The cat in the hat")
     => "The Cat In The Hat"

(capitalize "THE 77TH-HATTED CAT")
     => "The 77th-Hatted Cat"

(capitalize ?x)
     => 88

upcase-initials string Function
この関数は、string内の単語の先頭文字だけを大文字にし、 先頭文字以外の文字は変更しない。 この関数は、stringのコピーの各単語の先頭文字を大文字に変換したものを 内容とする新たな文字列を返す。

単語の定義は、現在の構文テーブル(See Syntax Class Table)において 単語構成文字に分類された文字が連続した列である。

(upcase-initials "The CAT in the hAt")
     => "The CAT In The HAt"

文字列を比較する関数については、See Text Comparison。 これらは、大文字小文字を区別しないものもあれば、 場合によって大文字小文字を区別しないものもある。


Node:Case Tables, Previous:Case Conversion, Up:Strings and Characters

大文字小文字テーブル

特別な大文字小文字テーブル(case table)をインストールすれば、 大文字小文字変換をカスタマイズできます。 大文字小文字テーブルは、大文字と小文字の対応関係を指定します。 このテーブルは、Lispオブジェクトの大文字小文字変換関数(前節参照)と バッファ内のテキストに作用する大文字小文字変換関数(see Case Changes)の 両方に影響します。 各バッファごとに大文字小文字テーブルがあります。 新たなバッファの大文字小文字テーブルを初期化するために使う 標準の大文字小文字テーブルもあります。

大文字小文字テーブルは、サブタイプがcase-tableである 文字テーブル(see Char-Tables)です。 この文字テーブルは、各文字を対応する小文字に対応付けます。 これには3つの追加スロットがあり、関連するテーブルを保持します。

upcase
upcase(大文字)テーブルは、各文字を対応する大文字に対応付ける。
canonicalize
canonicalize(正則)テーブルは大文字小文字に関連する1組の文字群を その文字群の特定のメンバに対応付ける。
equivalences
equivalences(同値)テーブルは、大文字小文字に関連する1組の文字群の各要素を その文字群内のつぎの文字に対応付ける。

単純な場合、必要なことは、小文字への対応付けを指定するだけです。 関連する3つのテーブルはこの対応付けから自動的に計算されます。

言語によっては、大文字と小文字の対応関係が1対1でないことがあります。 2つの異なる小文字が同じ大文字に対応することがあります。 このような場合、大文字から小文字への対応付けと、 小文字から大文字への対応付けの両方を指定する必要があります。

追加のテーブルcanonicalize(正則)は、各文字を正則文字に対応付けます。 2つの任意の文字が大文字小文字変換で関連付けられている場合、 その2つの文字は同一の正則文字を持ちます。 たとえば、aAは、大文字小文字変換で関連付けられているので、 これらは同一の正則文字を持つはずです (両方の文字に対してaであるか、両方の文字に対してAである)。

追加のテーブルequivalences(同値)は、 同じ正則クラス(同一の正則文字を持つ文字群)の文字を巡回して対応付けます。 (普通のASCIIでは、aAに対応付け、 Aaに対応付ける。 各正則クラスについても同様。)

大文字小文字テーブルを作成するときには、 canonicalize(正則)にはnilを指定できます。 そうすると、Emacsはこのスロットを小文字と大文字の対応付けから埋めます。 equivalences(同値)にもnilを指定できます。 そうすると、Emacsはこのスロットをcanonicalize(正則)から埋めます。 実際に使用している大文字小文字テーブルでは、 これらの要素はnil以外です。 canonicalize(正則)を指定せずに equivalences(同値)を指定しないでください、

つぎに、大文字小文字テーブルを操作する関数を示します。

case-table-p object Function
この述語は、objectが正しい 大文字小文字テーブルならばnil以外を返す。

set-standard-case-table table Function
この関数は、tableを標準の大文字小文字テーブルとし、 これ以降に作成する任意のバッファに使用できるようにする。

standard-case-table Function
これは、標準の大文字小文字テーブルを返す。

current-case-table Function
この関数は、カレントバッファの大文字小文字テーブルを返す。

set-case-table table Function
これは、カレントバッファの大文字小文字テーブルをtableとする。

以下の3つ関数は、非ASCII文字集合を定義するパッケージ向けの 便利なサブルーティンです。 これらは、指定した大文字小文字テーブルcase-tableを変更します。 さらに、標準の構文テーブルも変更します。 See Syntax Tables。 普通、標準の大文字小文字テーブルを変更するためにこれらの関数を使います。

set-case-syntax-pair uc lc case-table Function
この関数は対応する大文字と小文字を指定する。

set-case-syntax-delims l r case-table Function
この関数は、文字lrを 大文字小文字不変区切りの対応する対にする。

set-case-syntax char syntax case-table Function
この関数は、charを構文syntaxの大文字小文字不変にする。

describe-buffer-case-table コマンド
このコマンドは、カレントバッファの大文字小文字テーブルの内容を記述する。


Node:Lists, Next:, Previous:Strings and Characters, Up:Top

リスト

リスト(list)は、0個以上の(任意のLispオブジェクトの)要素の列を 表現します。 リストとベクトルの重要な相違点は、 複数のリストがそれらの構造の一部を共有できることです。 さらに、リスト全体をコピーすることなく、 リストに要素を追加したり削除できることです。


Node:Cons Cells, Next:, Up:Lists

リストとコンスセル

Lispのリストは基本データ型ではありません。 リストはコンスセル(cons cells)で構成されます。 コンスセルはドット対を表現するデータオブジェクトです。 ドット対は2つのLispオブジェクトを保持、つまり、『指し』ます。 その2つのLispオブジェクトの一方をCAR、他方をCDRといいます。 これらの名前は歴史的なものです。 See Cons Cell TypeCDRは『クダー』と読みます。

リストはコンスセルを連ねたものであり、 リストの各要素ごとにコンスセルが1つあります。 慣習として、コンスセルのCARはリストの要素であり、 CDRはリストを繋ぐために使います。 つまり、各コンスセルのCDRは後続のコンスセルです。 最後のコンスセルのCDRnilです。 CARCDRの非対称性は単なる慣習によるものです。 コンスセルのレベルでは、CARCDRには同じ性質があります。

ほとんどのコンスセルはリストの一部として使われるので、 リスト構造(list structure)という用語は、 コンスセルで構成した任意の構造を意味するようになりました。

シンボルnilは、シンボルであるとともにリストでもあるとみなします。 これは要素を持たないリストです。 慣習として、シンボルnilCDR(およびCAR)は nilであるとみなします。

空でない任意のリストlCDRは、 lの先頭要素を除くすべての要素を含んだリストです。


Node:Lists as Boxes, Next:, Previous:Cons Cells, Up:Lists

箱の対を連ねたリスト

コンスセルは1対の箱で図示できます。 最初の箱はCARを表し、2番目の箱はCDRを表します。 つぎは、2つのコンスセルから成る 2要素のリスト(tulip lily)を図示したものです。

 ---------------         ---------------
| car   | cdr   |       | car   | cdr   |
| tulip |   o---------->| lily  |  nil  |
|       |       |       |       |       |
 ---------------         ---------------

各1対の箱がコンスセルを表します。 各箱は、Lispオブジェクトを『参照する』、『指す』、『含む』のです。 (これらの用語は同義語。) 最初のコンスセルのCARを表す最初の箱は、 シンボルtulipを含みます。 最初のコンスセルのCDR箱から2番目のコンスセルへ向かう矢印は、 最初のコンスセルのCDRが2番目のコンスセルであることを表します。

同じリストは、つぎのような別の箱記法でも図示できます。

    --- ---      --- ---
   |   |   |--> |   |   |--> nil
    --- ---      --- ---
     |            |
     |            |
      --> tulip    --> lily

つぎは、より複雑で、最初の要素が2要素リストであるような 3要素リストを図示したものです。

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

同じリストを最初の箱記法で表現するとつぎのようになります。

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

コンスセルとリストの入力構文と表示表現、および、 『箱と矢印』によるリストの図示については、See Cons Cell Type


Node:List-related Predicates, Next:, Previous:Lists as Boxes, Up:Lists

リスト向け述語

以下の述語は、Lispオブジェクトが、アトムであるか、 コンスセル、つまり、リストであるか、 特別なオブジェクトnilであるか調べます。 (これらの多く述語は、それぞれ残りの述語で定義可能である。 しかし、多用するため、これらすべてを用意しておく価値がある。)

consp object Function
この関数は、objectがコンスセルならばtを返し、 さもなければnilを返す。 nilはコンスセルではないが、空リストである

atom object Function
この関数は、objectがアトムならばtを返し、 さもなければnilを返す。 コンスセルを除くすべてのオブジェクトはアトムである。 シンボルnilはアトムでもありリストでもある。 このようなLispオブジェクトはnilだけである。
(atom object) == (not (consp object))

listp object Function
この関数は、objectがコンスセルかnilならばtを返す。 さもなければnilを返す。
(listp '(1))
     => t
(listp '())
     => t

nlistp object Function
この関数は、listpの反対である。 objectがリストでなければtを返す。 さもなければnilを返す。
(listp object) == (not (nlistp object))

null object Function
この関数は、objectnilならばtを返し、 さもなければnilを返す。 この関数は、notと同一であるが、意図を明確にするために、 objectをリストと考えるときにはnullを使い、 objectを真理値と考えるときにはnotを使う (Combining Conditionsnotを参照)
(null '(1))
     => nil
(null '())
     => t


Node:List Elements, Next:, Previous:List-related Predicates, Up:Lists

リストの要素の参照

car cons-cell Function
この関数は、コンスセルcons-cellの最初のポインタが指す値を返す。 別のいい方をすれば、cons-cellCARを返す。

特別な場合として、cons-cellnilのときには、 carnilを返すと定義する。 したがって、任意のリストはcarの正しい引数である。 引数がコンスセルでもnilでもなければエラーを通知する。

(car '(a b c))
     => a
(car '())
     => nil

cdr cons-cell Function
この関数は、コンスセルcons-cellの2番目のポインタが指す値を返す。 別のいい方をすれば、cons-cellCDRを返す。

特別な場合として、cons-cellnilのときには、 cdrnilを返すと定義する。 したがって、任意のリストはcdrの正しい引数である。 引数がコンスセルでもnilでもなければエラーを通知する。

(cdr '(a b c))
     => (b c)
(cdr '())
     => nil

car-safe object Function
この関数は、コンスセルのCARを取り出すが、 他のデータ型に対するエラーを回避する。 objectがコンスセルならばobjectCARを返すが、 さもなければnilを返す。 これはcarと対照的であり、 carobjectがリストでないとエラーを通知する。
(car-safe object)
==
(let ((x object))
  (if (consp x)
      (car x)
    nil))

cdr-safe object Function
この関数は、コンスセルのCDRを取り出すが、 他のデータ型に対するエラーを回避する。 objectがコンスセルならばobjectCDRを返すが、 さもなければnilを返す。 これはcdrと対照的であり、 cdrobjectがリストでないとエラーを通知する。
(cdr-safe object)
==
(let ((x object))
  (if (consp x)
      (cdr x)
    nil))

nth n list Function
この関数は、listn番目の要素を返す。 要素は0から数えるので、listCARは要素番号0。 listの長さがnかそれ未満であると、値はnilになる。

nが負であると、nthlistの最初の要素を返す。

(nth 2 '(1 2 3 4))
     => 3
(nth 10 '(1 2 3 4))
     => nil
(nth -3 '(1 2 3 4))
     => 1

(nth n x) == (car (nthcdr n x))

関数eltも同様であるが、任意のシーケンスに適用できる。 歴史的な理由で引数の順序は逆である。 see Sequence Functions

nthcdr n list Function
この関数は、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 -3 '(1 2 3 4))
     => (1 2 3 4)

safe-length list Function
この関数は、エラーや無限ループを回避して、listの長さを返す。

listが実際にはリストでない場合には、safe-lengthは0を返す。 listに循環があると、少なくとも異なる要素の個数を表す有限値を返す。

循環はないと思われるリストの長さを計算するもっとも一般的な方法は、 lengthです。 See Sequence Functions

caar cons-cell Function
これは(car (car cons-cell))と同じ。

cadr cons-cell Function
これは(car (cdr cons-cell))(nth 1 cons-cell)と同じ。

cdar cons-cell Function
これは(cdr (car cons-cell))と同じ。

cddr cons-cell Function
これは(cdr (cdr cons-cell))(nthcdr 2 cons-cell)と同じ。


Node:Building Lists, Next:, Previous:List Elements, Up:Lists

コンスセルとリストの構築

リストはLispの中核なので、多くの関数はリストを構築します。 consは基本的なリスト構築関数です。 しかし、Emacsのソースコードでは、consよりlistを 多用していることは興味深いことです。

cons object1 object2 Function
この関数は、新たなリスト構造を構築するために使う基本関数。 object1CARobject2CDRとする 新たなコンスセルを作成し、このコンスセルを返す。 引数object1object2はどんなLispオブジェクトでもよいが、 ほとんどの場合、object2はリストである。
(cons 1 '(2))
     => (1 2)
(cons 1 '())
     => (1)
(cons 1 2)
     => (1 . 2)

consは、リストの先頭に要素を1つ追加するために しばしば使われる。 これを要素をリストにコンスするという。 たとえば、つぎのとおり。

(setq list (cons newelt list))

この例におけるlistという名前の変数と 以下に述べるlistという名前の関数とは衝突しない。 任意のシンボルはどちらの目的にも使える。

list &rest objects Function
この関数は、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

make-list length object Function
この関数は、すべての要素が同一の値objectであり 長さがlengthのリストを作成する。 make-stringと比較してほしい(see Creating Strings)。
(make-list 3 'pigs)
     => (pigs pigs pigs)
(make-list 0 'pigs)
     => nil

append &rest sequences Function
この関数はsequencesのすべての要素から成るリストを返す。 sequencesは、リスト、ベクトル、ブールベクトル、文字列のいずれかであるが、 普通、最後の要素はリストである。 最後の引数を除いてすべての引数をコピーするので、どの引数も変更しない (コピーせずにリストを繋ぐ方法については、 Rearrangementnconcを参照。)

一般には、appendの最後の引数はどんなLispオブジェクトでもよい。 最後の引数をコピーしたり変換したりしない。 それは、新たなリストの最後のコンスセルのCDRになる。 最後の引数がそれ自体リストであれば、それらの要素は、実質的には、 結果のリストの要素になる。 最後の要素がリストでなければ、結果は『ドット対』になる。 なぜなら、結果の最後のCDRは、 真のリストに必要とされるnilではないからである。

関数appendは、引数として整数も受け付ける。 整数を10進の表示表現の文字列に変換してから、 その文字列を整数のかわりに使う。 この機能を使わないでほしい。 削除する予定である。 読者がこの機能を使っていたら、今すぐプログラムを直すこと! 整数をこのような10進数に変換する正しい方法は、 format(see Formatting Strings)や number-to-string(see String Conversion)を使うことである。

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を導入するまでは、 リストをコピーする普通の方法でした。 See Sequences Arrays Vectors

appendの引数にベクトルと文字列を使った例をつぎに示します。

(append [a b] "cd" nil)
     => (a b 99 100)

apply(see Calling Functions)の助けを借りれば、 リストのリストの中にあるすべてのリストを連結できます。

(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になります。

reverse list Function
この関数は、listの要素を逆順にした新たなリストを作成する。 もとの引数listは変更しない
(setq x '(1 2 3 4))
     => (1 2 3 4)
(reverse x)
     => (4 3 2 1)
x
     => (1 2 3 4)


Node:Modifying Lists, Next:, Previous:Building Lists, Up:Lists

既存のリスト構造の修正

基本関数setcarsetcdrを使って、 コンスセルのCARCDRの内容を変更できます。 これらは、既存のリスト構造を変更するので、 『破壊的』な操作と呼びます。

Common Lispに関した注意: Common Lispでは、 リスト構造を変更するにはrplacarplacdを使う。 これらはsetcarsetcdrと同様に構造を変更する。 しかし、Common Lispの関数はコンスセルを返すが、 setcarsetcdrは新たなCARCDRを返す。


Node:Setcar, Next:, Up:Modifying Lists

setcarによるリスト要素の変更

コンスセルのCARを変更するには、setcarを使います。 リストに対して使用すると、 setcarはリストの1つの要素を別の要素に置き換えます。

setcar cons object Function
この関数は、consの新たなCARとしてobjectを格納し、 以前のCARを置き換える。 いいかえれば、consCARスロットがobjectを指すように変更する。 この関数は値objectを返す。 たとえば、つぎのようになる。
(setq x '(1 2))
     => (1 2)
(setcar x 4)
     => 4
x
     => (4 2)

コンスセルが複数のリストの共有構造の一部であるときには、 コンスセルに新たなCARを格納すると、 そのような各リストの1つの要素を変更することになります。

;; 共有部分がある2つのリストを作る
(setq x1 '(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)

変数x1x2に入っている共有部分を持つ2つのリストを図示すると つぎのようになります。 bを置き換えるとなぜ両者が変更されるのかわかるでしょう。

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


Node:Setcdr, Next:, Previous:Setcar, Up:Modifying Lists

リストのCDRの変更

CDRを修正するもっとも低レベルの基本関数はsetcdrです。

setcdr cons object Function
この関数は、consの新たなCDRとしてobjectを格納し、 以前のCDRを置き換える。 いいかえれば、consCDRスロットがobjectを指すように変更する。 この関数は値objectを返す。

リストのCDRを別のリストで置き換える例を示します。 リストの最初の要素以外は取り除かれ、 要素の別のシーケンスになります。 最初の要素は変更されません。 というのは、それはリストのCARの中にあり、 CDRからは辿れないからです。

(setq x '(1 2 3))
     => (1 2 3)
(setcdr x '(4))
     => (4)
x
     => (1 4)

リスト内のコンスセル群のCDRを変更することで、 リストの中ほどの要素を削除できます。 つぎの例は、リスト(a b c)の最初のコンスセルのCDRを変更することで、 このリストの第2要素bを削除します。

(setq x1 '(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番目のコンスセルはまだ存在していて、 そのCARもまだbですが、このリストの一部ではありません。

CDRを変更して新たな要素を挿入するのも同様に簡単です。

(setq x1 '(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------
        |       |       |
         ---------------


Node:Rearrangement, Previous:Setcdr, Up:Modifying Lists

リストの順序を変更する関数

以下は、リストを構成するコンスセルのCDRを変更することで、 『破壊的に』リストの順序を変更する関数です。 これらの関数を『破壊的』と呼ぶのは、 渡された引数であるもとのリストのコンスセルを繋ぎ換えて新たなリストに 変えるからです。

nconc &rest lists Function
この関数は、listsのすべての要素を入れたリストを返す。 append(see Building Lists)と異なり、 listsをコピーしない。 そのかわりに、各listsの最後のCDRを後続のリストを指すように変更する。 listsの最後は変更しない。 たとえば、つぎのようになる。
(setq x '(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 '(1 2 3))
     => (1 2 3)
(nconc x 'z)
     => (1 2 3 . z)
x
     => (1 2 3 . z)

しかしながら、すべての引数は(最後のものを除いて)リストである必要がある。

よくある落し穴は、nconcの最後以外の引数に、 クォートした定数リストを使うことである。 こうすると、読者のプログラムは実行するたびに定数を変えてしまう。 たとえば、つぎのようになる。

(defun add-foo (x)            ; この関数は引数の先頭に
  (nconc '(foo) x))           ;   fooを追加する、としたい

(symbol-function 'add-foo)
     => (lambda (x) (nconc (quote (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 (quote (foo 1 2 3 4) x)))

nreverse list Function
この関数は、listの要素の順番を逆順にする。 reverseと異なり、nreverseは リストを構成するコンスセルのCDRを逆向きにして引数を変えてしまう。 listの最後にあったコンスセルは戻り値の最初のコンスセルになる。

たとえば、つぎのようになる。

(setq x '(1 2 3 4))
     => (1 2 3 4)
x
     => (1 2 3 4)
(nreverse x)
     => (4 3 2 1)
;; 先頭にあったコンスセルは、今、最後になっている
x
     => (1)

混乱を避けるために、nreverseの結果は、 もとのリストを収めていたものと同じ変数に格納する。

(setq x (nreverse x))

nreverse(a b c)に適用した結果を図示すると つぎのようになる。

もとのリストの先頭                        逆順にしたリスト
 -------------        -------------        ------------
| car  | cdr  |      | car  | cdr  |      | car | cdr  |
|   a  |  nil |<--   |   b  |   o  |<--   |   c |   o  |
|      |      |   |  |      |   |  |   |  |     |   |  |
 -------------    |   --------- | -    |   -------- | -
                  |             |      |            |
                   -------------        ------------

sort list predicate Function
この関数は、破壊的にではあるが、 listを順序を保ってソートしたリストを返す。 要素の比較にはpredicateを使う。 順序を保ったソートとは、同じソートキーを持つ要素の相対順序を、 ソート実行前後で変更しないソートである。 異なる基準でつぎつぎにソートするときには、 順序を保つことは重要である。

引数predicateは、2つの引数を取る関数である必要がある。 この関数は、listの2つの要素で呼び出される。 昇順のソートでは、predicateは、 第1引数が第2引数より『小さい』ときにtを返し、 さもなければnilを返す必要がある。

比較関数predicateは、少なくとも単一のsortの呼び出し中は、 引数の任意の対に対して信頼できる結果を返す必要がある。 まず、反対称であること。 つまり、abより小さいときには、 baより小さくてはいけない。 また、遷移則が成り立つこと。 つまり、abより小さく、かつ、bcより小さいときには、 acより小さくなければならない。 これらの要請を満たさない比較関数を用いると、 sortの結果は予測できない。

sortが破壊的であるというのは、 listを構成するコンスセルのCDRを変更して、 コンスセルの順序を変更するからである。 非破壊的なソート関数では、ソートした要素を格納するために新たなコンスセルを 作成するであろう。 もとのリストを破壊せずにソートしたければ、 まずcopy-sequenceでコピーを作り、それをソートする。

ソートする際、listのコンスセルのCARは変更しない。 list内の要素aを入れていたコンスセルは、 ソート後にもそのCARにはaが入っている。 しかし、CDRを変更してあるので、リスト内では異なる場所に現れる。 たとえば、つぎのようになる。

(setq nums '(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が入っていないことに注意。 (numsが指す)コンスセルはソート前と同じコンスセルだが、 それはもはやリストの先頭にはない。 引数を保持していた変数が、 ソートしたリスト全体を保持していると仮定しないこと! かわりに、sortの結果を保存して、それを使う。 多くの場合、つぎのように、もとのリストを保持していた変数に結果を保存し直す。

(setq nums (sort nums '<))

ソートを行う他の関数については、see Sortingsortの有用な例については、 Accessing Documentationdocumentationを参照。


Node:Sets And Lists, Next:, Previous:Modifying Lists, Up:Lists

集合としてのリストの利用

リストで、数学の順序のない集合を表現できます。 つまり、リストに現れる要素を集合の要素と考え、 リスト内での順序は無視します。 2つの集合の和集合を作るには、 (要素が重複することを気にしなければ)appendを使います。 集合向けの他の有用な関数には、memqdelq、および、 これらのequal版であるmemberdeleteがあります。

Common Lispに関した注意: Common Lispには、集合演算向けに (要素の重複を避ける)関数unionintersectionがあるが、 GNU Emacs Lispにはない。 必要ならば、読者みずからLispでこれらを書ける。

memq object list Function
この関数は、objectlistの要素かどうか調べる。 そうならば、 memqobjectが最初に現れるところから始まるリストを返す。 さもなければnilを返す。 memqの文字qは、リストの要素に対するobjectの比較に eqを使うことを意味する。 たとえば、
(memq 'b '(a b c b a))
     => (b c b a)
(memq '(2) '((1) (2)))    ; (2)(2)eqではない
     => nil

delq object list Function
この関数は、listからobjecteqであるすべての要素を 破壊的に削除する。 delqの文字qは、memqと同様に、 リストの要素に対するobjectの比較にeqを使うことを意味する。

delqがリストの先頭から要素を削除する場合には、 単にリストを辿って削除した要素のつぎから始まる部分リストを返します。

(delq 'a '(a b c)) == (cdr '(a b c))

リストの中ほどの要素を削除する場合には、 削除にはCDRの変更を伴います(see Setcdr)。

(setq sample-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 'c sample-list)は、 3番目の要素を切り取ってsample-listを変更しますが、 (delq 'a sample-list)では、 なにも切り取らずに単に短いリストを返すことに注意してください。 引数listを保持していた変数が、実行後には少ない要素を持つと仮定したり、 もとのリストを保持し続けていると仮定したりしないでください! そのかわりに、delqの結果を保存して、それを使ってください。 多くの場合、つぎのように、 もとのリストを保持していた変数に結果を保存し直します。

(setq flowers (delq 'rose flowers))

つぎの例では、delqが一致を取ろうとしている(4)sample-list(4)とはeqではありません。

(delq '(4) sample-list)
     => (a c (4))

つぎの2つの関数は、memqdelqに似ていますが、 比較にはeqのかわりにequalを使います。 See Equality Predicates

member object list Function
関数memberは、equalを使ってobjectと要素を比較して、 objectlistの要素かどうか調べる。 objectが要素であれば、 memberlist内でそれが最初に現れるところから始まるリストを返す。 さもなければnilを返す。

memqと比較してほしい。

(member '(2) '((1) (2)))  ; (2)(2)equalである
     => ((2))
(memq '(2) '((1) (2)))    ; (2)(2)eqではない
     => nil
;; 同じ内容の2つの文字列はequalである
(member "foo" '("foo" "bar"))
     => ("foo" "bar")

delete object list Function
この関数は、listからobjectequalであるすべての要素を 破壊的に削除する。 membermemeqに対応するように、delqに対応する。 memberと同様に、 要素とobjectとの比較にはequalを使う。 一致する要素をみつけると、delqと同様に要素を削除する。 たとえば、つぎのとおり。
(delete '(2) '((2) (1) (2)))
     => ((1))

Common Lispに関した注意: GNU Emacs Lispの関数memberと関数deleteは Maclispから受け継いだものであり、Common Lispからではない。 Common Lisp版では要素の比較にはequalを使わない。

変数に格納したリストに要素を追加する別の方法については、 Setting Variablesの関数add-to-listを参照してください。


Node:Association Lists, Previous:Sets And Lists, Up:Lists

連想リスト

連想リスト(association list)、略してalistは、 キーから値への対応付けを記録しています。 これは連想(associations)と呼ばれるコンスセルのリストです。 各コンスセルのCARkeyであり、 CDR連想値(associated value)です。 6

連想リストの例を示します。 キーpineを値conesに、キーoakを値acornsに、 キーmapleを値seedsに対応付けています。

'((pine . cones)
  (oak . acorns)
  (maple . seeds))

連想リスト内の連想値は任意のLispオブジェクトでよく、キーもそうです。 たとえば、つぎの連想リストでは、シンボルaに数1を、 文字列"b"リスト(2 3)を対応付けています。 リスト(2 3)は連想リストの要素のCDRです。

((a . 1) ("b" 2 3))

要素のCDRCARに連想値を格納するように 連想リストを設計したほうがよい場合もあります。 つぎのようにします。

'((rose red) (lily white) (buttercup yellow))

ここで、redroseに対応付けた値と考えます。 この種の連想リストの利点の1つは、関連する別の情報を、 他の項目から成るリストでさえも、CDRCDRに格納できることです。 1つの欠点は、rassq(下記参照)を使って 指定した値を含む要素を探せないことです。 これらの条件が重要でない場合には、1つの連想リストに関する限り、 一貫性があればどちらを選ぶかは好みの問題です。

上に示した連想リストは、要素のCDRに連想値が収めてあると 考えることもできます。 roseの連想値はリスト(red)になります。

連想リストはスタックなどに置くような情報の記録に使います。 というには、リストの先頭に新たな連想を追加するのが簡単だからです。 指定したキーに対する連想を連想リストから探すとき、 それらが複数個存在する場合には、最初にみつかったものを返します。

Emacs Listでは、連想リストの要素がコンスセルでなくても エラーではありません。 連想リスト探索関数はそのような要素を単に無視します。 他の多くのLispでは、そのような場面ではエラーを通知します。

属性リストもいろいろな意味で連想リストに類似しています。 属性リストは、キーが一度しか現れない連想リストのようにふるまいます。 属性リストと連想リストの比較については、See Property Lists

assoc key alist Function
この関数は、alist内のkeyに対する最初の連想を返す。 keyと連想リストの各要素との比較には、 equal(see Equality Predicates)を用いる。 alistの中にCARkeyequalである連想が 存在しなければ、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-ignore-representationassoc-ignore-caseassocに似ていますが、 それらは比較にcompare-stringsを使う点が異なります。 See Text Comparison

rassoc value alist Function
この関数は、alistの中でvalueを値とする最初の連想を返す。 alistの中にCDRvalueequalである連想が 存在しなければ、nilを返す。

rassocassocに似ているが、 alistの各連想のCARのかわりにCDRを比較する点が異なる。 指定した値に対するキーを探す『assocの逆演算』と考えることができる。

assq key alist Function
この関数は、alist内のkeyに対する最初の連想を返すという意味で assocに似ているが、equalのかわりにeqで比較する。 alist内の連想のCARkeyeqであるものが存在しないと、 assqnilを返す。 この関数はassocより多用される。 というのは、eqequalより高速であり、 ほとんどの連想リストではキーとしてシンボルを使うからである。
(setq trees '((pine . cones) (oak . acorns) (maple . seeds)))
     => ((pine . cones) (oak . acorns) (maple . seeds))
(assq 'pine trees)
     => (pine . cones)

一方で、キーがシンボルではない連想リストでは、 assqは、通常、有用ではない。

(setq leaves
      '(("simple leaves" . oak)
        ("compound leaves" . horsechestnut)))

(assq "simple leaves" leaves)
     => nil
(assoc "simple leaves" leaves)
     => ("simple leaves" . oak)

rassq value alist Function
この関数は、alistの中でvalueを値とする最初の連想を返す。 alistの中にCDRvalueeqである連想が 存在しなければ、nilを返す。

rassqassqに似ているが、 alistの各連想のCARのかわりに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)CDRは、 シンボルwhiteではなくリスト(white)である。 連想をドット対記法で書くとこれが明確になる。

(lily white) == (lily . (white))

assoc-default key alist test default Function
この関数は、keyに一致するものをalistから探す。 alistの各要素について、(アトムならば)要素とkeyを、 あるいは、(コンスならば)要素のCARkeyを比較する。 比較にはこれらを2つの引数としてtestを呼び出す。 引数を渡す順序はこの順なので、 正規表現(see Regexp Search)を収めた連想リストに対して string-matchを使うと有益な結果を得られる。 testを省略したりnilであると、比較にはequalを用いる。

上の条件で連想リストの要素がkeyに一致するならば、 assoc-defaultはその要素に基づく値を返す。 要素がコンスならば値は要素のCDR。 さもなければ、戻り値はdefault

keyに一致する連想リストの要素が存在しなければ、 assoc-defaultnilを返す。

copy-alist alist Function
この関数は、alistを2レベルの深さまでコピーしたものを返す。 各連想ごとに新たなコピーを作るので、 新たな連想リストの連想を変更しても、もとの連想リストは変更しない。
(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")


Node:Sequences Arrays Vectors, Next:, Previous:Lists, Up:Top

シーケンス、配列、ベクトル

シーケンス(sequence)型とは、Lispの2つの異なる型の和であることを 思い出してください。 いいかえれば、任意のリストはシーケンスであり、 任意の配列もシーケンスです。 すべてのシーケンスに共通する性質は、 それぞれ、要素の順序付けた集まりであるということです。

配列(array)は、各要素ごとに1つ1つスロットを用意してある 単一の基本オブジェクトです。 すべての要素は一定時間内に参照できますが、既存の配列の長さは変更できません。 文字列、ベクトル、文字テーブル、ブールベクトルは、配列型の4つの型です。

リストは、要素を並べたものですが、 単一の基本オブジェクトではありません。 コンスセルから作られていて、1つの要素あたり1つのセルがあります。 n番目の要素を探すには、n個のコンスセルを調べる必要があるので、 リストの先頭から遠い要素を参照するには余計に時間がかかります。 しかし、リストには要素を追加したり削除したりできます。

以下の図は、これらの型の関係を示します。

     ┌────────────────────────┐
     │      シーケンス             │
     │┌───┐ ┌───────────────┐ │
     ││   │ │               │ │
     ││リスト│ │      配列       │ │
     ││   │ │ ┌────┐ ┌───┐  │ │
     ││   │ │ │    │ │   |  │ │
     │└───┘ │ │ベクトル│ │文字列|  │ │
     │      │ │    │ │   |  │ │
     │      │ └────┘ └───┘  │ │
     │      │ ┌────┐ ┌────┐ │ │
     │      │ │文字  │ │ブール │ │ │
     │      │ │テーブル│ │ベクトル│ │ │
     │      │ └────┘ └────┘ │ │
     │      └───────────────┘ │
     └────────────────────────┘

ベクトルやリストの要素は、どんなLispオブジェクトでもかまいません。 文字列の要素はすべて文字です。


Node:Sequence Functions, Next:, Up:Sequences Arrays Vectors

シーケンス

Emacs Lispでは、シーケンス(sequence)とはリストか配列のことです。 すべてのシーケンスに共通する性質は、 要素の順序付けた集まりであるということです。 本節では任意のシーケンスを受け付ける関数を説明します。

sequencep object Function
objectが、リスト、ベクトル、あるいは、文字列ならばtを返し、 さもなければnilを返す。

length sequence Function
この関数はsequence内の要素の個数を返す。 sequenceが(最後のCDRnilではないため) リストではないコンスセルであると、 エラーwrong-type-argumentを通知する。

関連する関数safe-lengthについては、see List Elements

(length '(1 2 3))
    => 3
(length ())
    => 0
(length "foobar")
    => 6
(length [1 2 3])
    => 3
(length (make-bool-vector 5 nil))
    => 5

elt sequence index Function
この関数はindexで添字付けされるsequenceの要素を返す。 indexの正当な値は、0からsequenceの長さより1小さい範囲の 整数である。 sequenceがリストである場合には、 範囲外のindexに対してはnilを返す。 さもなければエラーargs-out-of-rangeを引き起こす。
(elt [1 2 3 4] 2)
     => 3
(elt '(1 2 3 4) 2)
     => 3
;; stringを用いてeltが返す文字を明確にする
(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(see Array Functions)や nth(see List Elements)を汎用にしたものである。

copy-sequence sequence Function
sequenceのコピーを返す。 コピーは、もとのシーケンスと同じ型のオブジェクトであり、 同じ要素が同じ順序で入っている。

コピーに新たな要素を格納しても、もとのsequenceには影響せず、 その逆もそうである。 しかし、新たなシーケンスの要素はコピーしていない。 つまり、それらはもとの要素と同一(eq)である。 したがって、シーケンスのコピーにおいて、 それらの要素の内部を変更すると、もとのシーケンスでもその変更がわかる。

シーケンスがテキスト属性を持つ文字列である場合には、 コピーの中の属性リストそのものもコピーであり、 もとの属性リストを共有するのではない。 しかし、属性の実際の値は共有される。

シーケンスをコピーする別の方法については、 Building ListsappendCreating StringsconcatVectorsvconcatを参照。

(setq bar '(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

;; 1つのシーケンスの1つの要素を置き換える
(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)]


Node:Arrays, Next:, Previous:Sequence Functions, Up:Sequences Arrays Vectors

配列

配列(array)オブジェクトには、配列の要素と呼ばれる Lispオブジェクトを保持するためのスロットがいくつかあります。 配列の任意の要素は一定時間で参照できます。 一方、リストの要素の参照には、 リスト内でのその要素の位置に比例した時間が必要です。

Emacsには4つの型の配列があり、すべて1次元です。 文字列(strings)、ベクトル(vectors)、 ブールベクトル(bool-vectors)、文字テーブル(char-tables)です。 ベクトルは汎用の配列であり、 その要素は任意のLispオブジェクトでかまいません。 文字列は特化された配列であり、その要素は文字(つまり、0から255までの整数)で ある必要があります。 配列のそれぞれの型には、独自の入力構文があります。 String TypeとSee Vector Type

配列の4つの型すべてには、以下の性質があります。

文字テーブル以外の配列を作成するときには、 その長さを指定する必要があります。 文字テーブルの長さは指定できません。 というのは、その長さは文字コードの範囲で決まるからです。

原理的には、テキスト文字の配列が必要ならば文字列かベクトルを使います。 実用上は、以下の4つの理由から、そのような場合には文字列を使います。

一方、(キー列のような)キーボード入力文字の配列には、 ベクトルが必要です。 というのは、キーボード入力文字の多くは、文字列に納まる範囲外だからです。 See Key Sequence Input


Node:Array Functions, Next:, Previous:Arrays, Up:Sequences Arrays Vectors

配列操作関数

本節では任意の配列型を受け付ける関数を説明します。

arrayp object Function
この関数はobjectが配列 (つまり、ベクトル、文字列、ブールベクトル、あるいは、文字テーブル)ならば、 tを返す。
(arrayp [a])
     => t
(arrayp "asdf")
     => t
(arrayp (syntax-table))    ;; 文字テーブル
     => t

aref array index Function
この関数はarrayindex番目の要素を返す。 最初の要素の添字は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
Sequence Functionsの関数eltも参照。

aset array index object Function
この関数は配列arrayindex番目の要素にobjectを設定する。 objectを返す。
(setq w [foo bar baz])
     => [foo bar baz]
(aset w 0 'fu)
     => fu
w
     => [fu bar baz]

(setq x "asdfasfd")
     => "asdfasfd"
(aset x 3 ?Z)
     => 90
x
     => "asdZasfd"

arrayが文字列であり、かつ、objectが文字でなければ、 結果はエラーwrong-type-argumentとなる。 arrayが文字列であり、かつ、objectが文字であっても、 現在(aref object index)に保存されている文字のバイト数と objectが使うバイト数が異なれば、やはり、エラーとなる。 see Splitting Characters

fillarray array object Function
この関数は、配列arrayobjectで埋め、 arrayの各要素がobjectとなるようにする。 arrayを返す。
(setq a [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 "When in the course")
     => "When in the course"
(fillarray s ?-)
     => "------------------"

arrayが文字列であり、かつ、objectが文字でなければ、 結果はエラーwrong-type-argumentになる。

配列であることが既知のオブジェクトに対しては、 汎用のシーケンス関数copy-sequencelengthがしばしば有用です。 See Sequence Functions


Node:Vectors, Next:, Previous:Array Functions, Up:Sequences Arrays Vectors

ベクトル

Lispの配列は、ほとんどの言語の配列と同様に、 その要素を一定時間で参照可能なメモリのブロックです。 ベクトル(vector)は指定長の汎用配列です。 その要素はどんなLispオブジェクトでもかまいません。 (対照的に、文字列は要素としては文字だけを保持する。) Emacsでは、オブジェクト配列obarray(シンボルのベクトル)、 キーマップ(コマンドのベクトル)の一部にベクトルを使っています。 これらは、内部的には、バイトコード関数の表現の一部にも使っています。 そのような関数を表示すると、その中にベクトルがあるのがわかります。

Emacs Lispでは、ベクトルの要素の添字は0から始まります。

ベクトルは要素を角括弧で囲んで表示します。 したがって、要素がシンボルabaであるベクトルは、 [a b a]と表示されます。 Lispへの入力では同じようにベクトルを書きます。

文字列や数と同様に、評価上、ベクトルは定数とみなします。 それを評価した結果は、同じベクトルです。 この評価では、ベクトルの要素を評価したり調べたりはしません。

以下は、これらの原理を例示するものです。

(setq avector [1 two '(three) "four" [five]])
     => [1 two (quote (three)) "four" [five]]
(eval avector)
     => [1 two (quote (three)) "four" [five]]
(eq avector (eval avector))
     => t


Node:Vector Functions, Next:, Previous:Vectors, Up:Sequences Arrays Vectors

ベクトル向け関数

ベクトルに関連した関数はつぎのとおりです。

vectorp object Function
この関数は、objectがベクトルならばtを返す。
(vectorp [a])
     => t
(vectorp "asdf")
     => nil

vector &rest objects Function
この関数は、引数objectsを要素とするベクトルを作成しそれを返す。
(vector 'foo 23 [bar baz] "rats")
     => [foo 23 [bar baz] "rats"]
(vector)
     => []

make-vector length object Function
この関数は、各要素をobjectに初期化した length個の要素から成る新たなベクトルを返す。
(setq sleepy (make-vector 9 'Z))
     => [Z Z Z Z Z Z Z Z Z]

vconcat &rest sequences Function
この関数は、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は、引数としてバイトコード関数でも受け付ける。 これは、バイトコード関数オブジェクトの全内容を簡単に参照できるように するための特別な機能である。 see Byte-Code Objects

関数vconcatは、引数として整数も受け付ける。 整数はその10進の表示表現の文字列に変換してから、 その文字列を整数のかわりに使う。 この機能を使わないでほしい。 削除する予定である。 読者がこの機能を使っていたら、今すぐプログラムを直すこと! 整数をこのような10進数に変換する正しい方法は、 format(see Formatting Strings)や number-to-string(see String Conversion)を使うことである。

他の連結関数については、 Mapping FunctionsmapconcatCreating StringsconcatBuilding Listsappendを参照。

関数appendは、ベクトルを同じ要素から成るリストへ変換する便利な方法です (see Building Lists)。

(setq avector [1 two (quote (three)) "four" [five]])
     => [1 two (quote (three)) "four" [five]]
(append avector nil)
     => (1 two (quote (three)) "four" [five])


Node:Char-Tables, Next:, Previous:Vector Functions, Up:Sequences Arrays Vectors

文字テーブル

文字テーブルはベクトルによく似ていますが、 文字コードで添字付けする点が異なります。 修飾子を伴わない任意の正当な文字コードは、文字テーブルの添字に使えます。 文字テーブルの要素は、任意の配列のように、arefasetで 参照できます。 さらに、文字テーブルでは、 特定の文字コードには対応しない追加データを保持するための追加スロットを 保持できます。 評価時には、文字テーブルは定数です。

各文字テーブルには、シンボルであるサブタイプ(subtype)があります。 サブタイプには2つの目的があります。 異なる使い方をする文字テーブルを区別するためと、 追加スロットの個数を制御するためです。 たとえば、表示テーブルはサブタイプがdisplay-tableである 文字テーブルであり、 構文テーブルはサブタイプがsyntax-tableである文字テーブルです。 正当なサブタイプには、char-table-extra-slots属性があるはずで、 その値は0から10までの整数です。 この整数が文字テーブルの追加スロットの個数を指定します。

文字テーブルは、別の文字テーブルであるを持てます。 その場合、特定の文字cに対する文字テーブルの指定がnilのときには、 親において指定された値を継承します。 いいかえれば、char-table自体にnilを指定してあると、 (aref char-table c)は、 char-tableの親の値を返します。

文字テーブルは、デフォルト値も持てます。 その場合、文字テーブルが指定する値がnilであると、 (aref char-table c)はデフォルト値を返します。

make-char-table subtype &optional init Function
サブタイプがsubtypeである新たに作成した文字テーブルを返す。 各要素をinitで初期化する。 なお、initのデフォルトはnilである。 文字テーブル作成後には、文字テーブルのサブタイプは変更できない。

文字テーブルの長さを指定する引数はない。 なぜなら、すべての文字テーブルでは、 任意の正当な文字コードを添字として使えるからである。

char-table-p object Function
この関数は、objectが文字テーブルならばtを返し、 さもなければnilを返す。

char-table-subtype char-table Function
この関数はchar-tableのサブタイプを表すシンボルを返す。

set-char-table-default char-table new-default Function
この関数はchar-tableのデフォルト値をnew-defaultにする。

文字テーブルのデフォルト値を参照するための特別な関数はない。 それには(char-table-range char-table nil)を使う。

char-table-parent char-table Function
この関数はchar-tableの親を返す。 親は、nilであるか他の文字テーブルである。

set-char-table-parent char-table new-parent Function
この関数はchar-tableの親をnew-parentにする。

char-table-extra-slot char-table n Function
この関数はchar-tableの追加スロットnの内容を返す。 文字テーブル内の追加スロットの個数はそのサブタイプで決まる。

set-char-table-extra-slot char-table n value Function
この関数はchar-tableの追加スロットnvalueを格納する。

文字テーブルでは、1つの文字コードに対して1つの要素値を指定できます。 また、文字集合全体に対して1つの値を指定することもできます。

char-table-range char-table range Function
これは、char-tableにおいて文字範囲rangeに指定されている値を返す。 rangeとして可能なものは以下のとおり。
nil
デフォルト値を指す。
char
charが正当な文字コードであると仮定して) 文字charに対する要素を指す。
charset
文字集合charset全体に対して指定してある値を指す (see Character Sets)。
generic-char
文字集合に対する汎用文字を表す。 引数として汎用文字を指定することは、文字集合名を指定することと同値。 汎用文字の説明は、see Splitting Characters

set-char-table-range char-table range value Function
この関数は文字範囲rangeに対するchar-tableの値を設定する。 rangeとして可能なものは以下のとおり。
nil
デフォルト値を指す。
t
文字コードの範囲全体を指す。
char
charが正当な文字コードであると仮定して) 文字charに対する要素を指す。
charset
文字集合charset全体に対して指定してある値を指す (see Character Sets)。
generic-char
文字集合に対する汎用文字を表す。 引数として汎用文字を指定することは、文字集合名を指定することと同値。 汎用文字の説明は、see Splitting Characters

map-char-table function char-table Function
この関数は、char-tableの各要素についてfunctionを呼び出す。 functionをキーと値の2つの引数で呼び出す。 キーはchar-table-rangeに対する可能なrange引数であり、 正当な文字か汎用文字である。 値は(char-table-range char-table key)である。

全体として、functionに渡すキー・値の対は、 char-tableに格納されたすべての値を表す。

戻り値はつねにnilである。 この関数が有用であるようにするには、 functionには副作用があるべきである。 たとえば、つぎは構文テーブルの各要素の調べ方である。

(let (accumulator)
  (map-char-table
   #'(lambda (key value)
       (setq accumulator
             (cons (list key value) accumulator)))
   (syntax-table))
  accumulator)
=>
((475008 nil) (474880 nil) (474752 nil) (474624 nil)
 ... (5 (3)) (4 (3)) (3 (3)) (2 (3)) (1 (3)) (0 (3)))


Node:Bool-Vectors, Previous:Char-Tables, Up:Sequences Arrays Vectors

ブールベクトル

ブールベクトルはベクトルによく似ていますが、 tnilの値だけを保存できる点が異なります。 ブールベクトルの要素にnil以外の値を保存しようとすると、 その効果はtを保存することになります。 すべての配列と同様に、ブールベクトルの添字は0から始まり、 ブールベクトルをいったん作成すると長さは変更できません。 評価時には、ブールベクトルは定数です。

ブールベクトルを操作する特別な関数は2つあります。 それに加えて、他の種類の配列を扱う関数でも操作できます。

make-bool-vector length initial Function
initialに初期化した長さlengthの新たなブールベクトルを返す。

bool-vector-p object Function
objectがブールベクトルであればtを返し、 さもなければnilを返す。


Node:Symbols, Next:, Previous:Sequences Arrays Vectors, Up:Top

シンボル

シンボル(symbol)とは、一意な名前が付いたオブジェクトです。 本章では、シンボル、その構成要素、属性リスト、作成方法とインターン方法に ついて説明します。 シンボルの変数としての使用方法、関数名としての使用方法について説明した 別の章もあります。 VariablesとSee Functions。 シンボルの正確な入力構文については、See Symbol Type

symbolpで、任意のLispオブジェクトがシンボルかどうか調べられます。

symbolp object Function
この関数は、objectがシンボルならばtを返し、 さもなければnilを返す。


Node:Symbol Components, Next:, Previous:Symbols, Up:Symbols

シンボルの構成要素

各シンボルには4つの構成要素(つまり、『セル』)があり、 それぞれで別のオブジェクトを参照します。

表示名(print name)
表示名セル(print name cell)には、 シンボルの入力や表示に使う名前である文字列が入っている。 Creating Symbolssymbol-nameを参照。
値(value)
値セル(value cell)には、 シンボルの変数としての現在値が入っている。 シンボルをフォームとして使用したとき、 フォームの値はシンボルの値セルの内容である。 Accessing Variablessymbol-valueを参照。
関数(function)
関数セル(function cell)には、シンボルの関数定義が入っている。 シンボルを関数として使用したとき、その関数定義を使う。 シンボルが、編集コマンドを実行するためのキーマップやキーボードマクロを 表すときもこのセルを使う。 各シンボルには値セルと関数セルが別々にあるので、 変数名と関数名は衝突しない。 Function Cellssymbol-functionを参照。
属性リスト(property list)
属性リストセル(property list cell)には、 シンボルの属性リストが入っている。 Property Listssymbol-plistを参照。

表示名セルはつねに文字列を保持していて、変更できません。 他の3つのセルには、任意の指定したLispオブジェクトを個別に設定できます。

表示名セルは、シンボルの名前である文字列を保持しています。 シンボルはテキスト上はその名前で表現されるので、 2つのシンボルが同じ名前を持たないことが重要です。 Lispリーダがこのことを保証します。 シンボルを読み取るたびに、新たにシンボルを作成するまえに、 指定した名前のシンボルが存在するかどうか調べます。 (GNU Emacs Lispでは、これにはハッシュアルゴリズムと オブジェクト配列obarrayを使う。 see Creating Symbols。)

普通の使い方では、関数セルには関数(see Functions)や マクロ(see Macros)が入っていて、 Lispインタープリタはそのように仮定します(see Evaluation)。 シンボルの関数セルには、 キーボードマクロ(see Keyboard Macros)、キーマップ(see Keymaps)、 自動ロードオブジェクト(see Autoloading)が入っていることもあります。 『関数foo』といった場合、実際には、シンボルfooの関数セルに 入っている関数を意味します。 必要な場合に限って区別します。

属性リストセルは、通常、正しい形式の属性リスト(see Property Lists)が 入っている必要があり、さまざまな関数がそのように仮定しています。

関数セルや値セルは(void)でもかまいません。 つまり、セルはどんなオブジェクトも指していません。 (このことは、シンボルvoidを保持しているとか、 シンボルnilを保持しているのとは違う。) 空である関数セルや値セルを参照すると、 その結果はSymbol's value as variable is void (「変数としてのシンボルの値は空」)のようなエラーになります。

4つの関数、symbol-namesymbol-valuesymbol-plistsymbol-functionは、 シンボルの4つのセルの内容を返します。 以下に、シンボルbuffer-file-nameの 4つのセルの内容を表示する例を示します。

(symbol-name 'buffer-file-name)
     => "buffer-file-name"
(symbol-value 'buffer-file-name)
     => "/gnu/elisp/symbols.texi"
(symbol-plist 'buffer-file-name)
     => (variable-documentation 29529)
(symbol-function 'buffer-file-name)
     => #<subr buffer-file-name>

このシンボルは、カレントバッファで訪問しているファイルの名前を保持するので、 値セルの内容は本書Emacs Lispマニュアルの本章のソースファイルの名前です。 属性リストセルには、リスト(variable-documentation 29529)が入っていて、 ドキュメント関数に対してファイルDOC-versionのどこに 変数buffer-file-nameの説明文字列が入っているか伝えます。 (29529は、当該説明文字列の開始位置を表す DOC-versionの先頭からのオフセット。 Documentation Basicsを参照。) 関数セルには、ファイルの名前を返す関数が入っています。 buffer-file-nameは基本関数の名前です。 これには入力構文はなく、 ハッシュ記法(see Primitive Function Type)で表示されています。 Lispで書いた関数を表すシンボルでは、 このセルにラムダ式(あるいはバイトコードオブジェクト)が入っています。


Node:Definitions, Next:, Previous:Symbol Components, Up:Symbols

シンボルを定義する

Lispにおける定義(definition)とは、 特定のシンボルをどのように使うかを意思表示するスペシャルフォームです。 Emacs Lispでは、シンボルを変数と定義したり、 関数(あるいはマクロ)と定義したり、あるいは、それらを独立に定義できます。

定義を行う構文では、典型的には、値を指定したり、 シンボルを特定の使い方をすると指定したりし、 さらに、そのような使い方をしたときの意味を表すための説明文字列を指定します。 したがって、シンボルを変数として定義するときには、 変数に初期値を与え、その変数の説明文字列を指定できます。

defvardefconstは、シンボルをグローバル変数として定義する スペシャルフォームです。 これらはDefining Variablesで詳しく説明してあります。 カスタマイズ可能なようにユーザーオプション用の変数を定義するには、 defcustom(see Customization)を使います。

defunは、シンボルを関数として定義し、 ラムダ式を作ってシンボルの関数セルに格納します。 したがって、このラムダ式がシンボルの関数定義になります。 (用語『関数定義』は、関数セルの内容を意味し、 defunがシンボルに関数としての定義を与えることからきている。) defsubstdefaliasは、関数を定義する別の2つの方法です。 See Functions

defmacroは、シンボルをマクロとして定義します。 マクロオブジェクトを作ってシンボルの関数セルに格納します。 シンボルは、マクロか関数のいずれかであって、 同時に両方にはならないことに注意してください。 というのは、マクロ定義も関数定義も関数セルに収められ、 そのセルにはどんなときでもたった1つのLispオブジェクトしか 保持できないからです。 See Macros

Emacs Lispでは、シンボルを変数や関数として使うための 定義は必須ではありません。 したがって、シンボルをあらかじめ定義しようがしまいが、 setqを使ってシンボルをグローバル変数にできます。 定義の真の目的は、プログラマに対する指針であり、プログラミングツールなのです。 これらは、コードを読むプログラマに対して、 特定のシンボルを変数として使うのか関数として使うのか、 その意図を伝えます。 さらに、etagsmake-docfileなどのユーティリティは、 定義を認識してタグテーブルやファイルDOC-versionに 適切な情報を追加します。 See Accessing Documentation


Node:Creating Symbols, Next:, Previous:Definitions, Up:Symbols

シンボルの作成とインターン

GNU Emacs Lispにおいて、どのようにシンボルを作成するかを理解するには、 Lispがそれらをどのように読むかを知る必要があります。 Lispは、同じ文字群を読み取るたびに、同じシンボルをみつけることを保証する 必要があります。 これに失敗すると完全に混乱します。

Lispリーダがシンボルに出会うと、名前の文字群をすべて読み取ります。 そして、これらの文字群を『ハッシュ化』して、 オブジェクト配列(obarray)と呼ばれる表の添字を探します。 ハッシュ化は効率的に探索する手法です。 たとえば、Jan Jonesを電話番号簿の表紙から1ページずつ順に探すかわりに、 Jのページから探し始めます。 これは単純なハッシュ化です。 オブジェクト配列の各要素は、 あるハッシュコードを有するすべてのシンボルを格納した バケット(bucket)です。 ある名前を探すには、その名前のハッシュコードに対応するバケット内の すべてのシンボルを調べるだけで十分です。

目的の名前のシンボルがみつかれば、リーダはそのシンボルを使います。 オブジェクト配列に目的の名前のシンボルがなければ、 リーダは新たなシンボルを作成し、それをオブジェクト配列に追加します。 ある名前のシンボルを探したり追加することをシンボルを インターン(interning)するといい、 そのシンボルをインターンしたシンボル(interned symbol)と呼びます。

インターンすることで、各オブジェクト配列には 特定の名前のシンボルが1個だけあることを保証します。 他の似たような名前のシンボルが存在しても、 同じオブジェクト配列には入っていません。 したがって、同じオブジェクト配列を使って読む限り、 リーダは同じ名前に対して同じシンボルを得ることができます。

すべてのシンボルがオブジェクト配列に入っているとは限りません。 実際、どのオブジェクト配列にも属さないシンボルがいくつかあります。 これらをインターンしてないシンボル(uninterned symbols)と呼びます。 インターンしてないシンボルにも、他のシンボルと同様に4つのセルがあります。 しかし、それを参照する手段は、他のオブジェクトを介して探すか、 変数の値として探すしかありません。

Emacs Lispでは、オブジェクト配列は実際にはベクトルです。 ベクトルの各要素はバケットです。 その値は、そのバケットにハッシュ化される名前のインターンしたシンボルであるか、 そのバケットが空ならば0です。 インターンした各シンボルには、バケットのつぎのシンボルを指す (ユーザーには見えない)内部的なリンクがあります。 このリンクは見えないので、mapatoms(下記)を使う以外には、 オブジェクト配列内のすべてのシンボルを探す方法はありません。 バケット内でのシンボルの順序は関係ありません。

空のオブジェクト配列では、各要素は0です。 (make-vector length 0)でオブジェクト配列を作成できます。 これは、オブジェクト配列を作成する唯一の正当な方法です。 長さとして素数を用いると、ハッシュ化の結果がよい傾向があります。 2の巾より1小さい長さもよい結果になります。

読者自身でオブジェクト配列にシンボルを入れないでください。 うまくいきません。 オブジェクト配列にシンボルを正しく入れられるのはinternだけです。

Common Lispに関した注意: Common Lispでは、1つのシンボルを複数のオブジェクト配列に入れることができる。

下記の関数のほとんどは、引数に名前を取り、 場合によってはオブジェクト配列を引数に取ります。 名前が文字列でなかったり、オブジェクト配列がベクトルでないと、 エラーwrong-type-argumentを通知します。

symbol-name symbol Function
この関数は、symbolの名前を表す文字列を返す。 たとえば、つぎのとおり。
(symbol-name 'foo)
     => "foo"

警告: 文字列の文字を置き換えるとシンボルの名前を変更するが、 オブジェクト配列は更新できないので変更しないこと!

make-symbol name Function
この関数は、name(文字列であること)を名前とする 新たに割り付けたインターンしていないシンボルを返す。 その値と関数定義は空であり、属性リストはnilである。 以下の例では、symの値はfooeqではない。 なぜなら、名前はfooではあるが、 インターンしていない別のシンボルであるため。
(setq sym (make-symbol "foo"))
     => foo
(eq sym 'foo)
     => nil

intern name &optional obarray Function
この関数は、nameを名前とするインターンしたシンボルを返す。 そのようなシンボルがオブジェクト配列obarrayに存在しなければ、 internは新たなものを作成し、それをオブジェクト配列に追加してから、 それを返す。 obarrayを省略すると、グローバル変数obarrayの値を使う。
(setq sym (intern "foo"))
     => foo
(eq sym 'foo)
     => t

(setq sym1 (intern "foo" other-obarray))
     => foo
(eq sym 'foo)
     => nil

Common Lispに関した注意: Common Lispでは、既存のシンボルをオブジェクト配列にインターンできる。 Emacs Lispでは、これはできない。 なぜなら、internの引数は文字列である必要があり、 シンボルではない。

intern-soft name &optional obarray Function
この関数は、obarray内のnameを名前とするシンボルを返す。 ただし、その名前のシンボルがobarrayになければnilを返す。 したがって、intern-softを用いて、指定した名前のシンボルが インターンされているかどうか調べられる。 obarrayを省略すると、グローバル変数obarrayの値を使う。
(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

obarray Variable
この変数は、internreadが使う標準のオブジェクト配列。

mapatoms function &optional obarray Function
この関数は、オブジェクト配列obarrayの各シンボルについて、 1回ずつ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を使った別の例については、 Accessing Documentationdocumentationを参照。

unintern symbol &optional obarray Function
この関数は、オブジェクト配列obarrayからsymbolを削除する。 symbolが実際にはオブジェクト配列内になければ、 uninternはなにもしない。 obarraynilであると、現在のオブジェクト配列を使う。

symbolのシンボルのかわりに文字列を指定すると、 それはシンボルの名前を表す。 そして、uninternはその名前のシンボルを(あれば)オブジェクト配列から 削除する。 そのようなシンボルがなければ、uninternはなにもしない。

uninternは、シンボルを削除したときにはtを返す。 さもなければnilを返す。


Node:Property Lists, Previous:Creating Symbols, Up:Symbols

属性リスト

属性リスト(property list、略してplist)とは、 シンボルの属性リストセルに格納された対になった要素から成るリストです。 各対は、属性名(通常、シンボル)を属性、すなわち、属性値に対応付けます。 属性リストは、一般に、シンボルに関する情報を記録します。 変数としての説明文字列、定義されているファイルの名前、 言語理解システムにおいては(語を表す)シンボルの文法クラスなどです。

文字列内やバッファ内の文字位置も属性リストを持てます。 See Text Properties

属性リスト内の属性名と属性値は、任意のLispオブジェクトでかまいませんが、 普通、属性名はシンボルです。 属性リスト関数は、eqを使って属性名を比較します。 コンパイラをロードした際のシンボルprognの属性リストをつぎに示します。

(lisp-indent-function 0 byte-compile byte-compile-progn)

ここで、lisp-indent-functionbyte-compileは属性名であり、 他の2つの要素は対応する属性値です。


Node:Plists and Alists, Next:, Up:Property Lists

属性リストと連想リスト

連想リスト(see Association Lists)は、 属性リストに非常によく似ています。 連想リストと異なり、属性名は一意である必要があるので、 属性リスト内での対の出現順序は関係ありません。

さまざまなLisp関数やLisp変数に情報を付加するには、 属性リストは連想リストより優れています。 読者のプログラムで1つの連想リストにすべての連想を入れておいたとすると、 1つの連想を探すたびに、リスト全体を探索する必要があります。 これには時間がかかります。 一方、同じ情報を関数名や変数自身の属性リストに保持しておけば、 各探索では1つの属性リストを走査するだけでよく、 属性リストは、普通、短いものです。 このため、変数の説明文字列をvariable-documentationという名前の 属性に記録しているのです。 同様に、バイトコンパイラも、 特別な処理が必要な関数を属性を使って記録しています。

しかしながら、連想リストにもそれ独自の利点があります。 読者のアプリケーションに依存しますが、 属性を更新するより、連想リストの先頭に連想を追加するほうが速いです。 あるシンボルのすべての属性は同一の属性リストに格納してあるので、 1つの属性名を異なる目的に使うと衝突します。 (この理由から、プログラムで普通に使う 変数名や関数名の接頭辞で始まる属性名を選ぶなどして、 一意な属性名を選ぶのがよい。) 連想リストは、リストの先頭に要素を追加し、先頭から要素を削除するので、 スタックのように使えます。 属性リストでは、これは不可能です。


Node:Symbol Plists, Next:, Previous:Plists and Alists, Up:Property Lists

シンボル向け属性リスト関数

symbol-plist symbol Function
この関数はsymbolの属性リストを返す。

setplist symbol plist Function
この関数は、symbolの属性リストを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)

普通の使い方を意図していない特別なオブジェクト配列内のシンボルに対しては、 属性リストセルの非標準な使い方にも意味があろう。 実際、略語機構(see Abbrevs)ではそのようにしている。

get symbol property Function
この関数は、symbolの属性リストから propertyという名前の属性の値を探す。 そのような属性がなければ、nilを返す。 つまり、nilという値と属性の欠如を区別できない。

名前propertyは既存の属性名とeqで比較するため、 どんなオブジェクトでも正当な属性である。

例については、putを参照。

put symbol property value Function
この関数は、symbolの属性リストにおいて、 属性名propertyの古い属性値をvalueで置き換える。 関数putvalueを返す。
(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))


Node:Other Plists, Previous:Symbol Plists, Up:Property Lists

シンボルの外部の属性リスト

シンボル以外の場所に保存した属性リストの操作に便利な2つの関数があります。

plist-get plist property Function
これは、属性リストplistに保存されている属性propertyの値を返す。 たとえば、つぎのとおり。
(plist-get '(foo 4) 'foo)
     => 4

plist-put plist property value Function
これは、属性リストplistに、 propertyの値としてvalueを格納する。 これはplistを破壊的に変更するか、あるいは、 古いものを変更せずに新たなリスト構造を構築する。 関数は変更した属性リストを返すので、 plistを保持していたところへ保存し直せる。 たとえば、つぎのとおり。
(setq my-plist '(bar t foo 4))
     => (bar t foo 4)
(setq my-plist (plist-put my-plist 'foo 69))
     => (bar t foo 69)
(setq my-plist (plist-put my-plist 'quux '(a)))
     => (bar t foo 69 quux (a))

つぎのようにして、plist-putを用いてputを定義できます。

(defun put (symbol prop value)
  (setplist symbol
            (plist-put (symbol-plist symbol) prop value)))


Node:Evaluation, Next:, Previous:Symbols, Up:Top

評価

Emacs Lispにおける式の評価(evaluation)は、 Lispインタープリタ(Lisp interpreter)が行います。 これは、入力としてLispオブジェクトを受け取り、 式としての値を計算するプログラムです。 計算方法は、本章で述べる規則に従ってオブジェクトのデータ型に依存します。 インタープリタは、読者のプログラムのある部分を評価するために 自動的に動作しますが、Lisp基本関数evalを介して インタープリタを明示的に呼ぶ出すこともできます。

評価することを意図したLispオブジェクトを (expression)とかフォーム(form)と呼びます。 式はデータオブジェクトであり単なるテキストではないという事実は、 Lisp様言語と典型的なプログラム言語との基本的な違いの1つです。 どんなオブジェクトでも評価できますが、実用上は、 数、シンボル、リスト、文字列を評価することが多いのです。

Lisp式を読み取りその式を評価することはとても一般的なことですが、 読み取りと評価は別々の動作であり、それぞれを別々に実行することもできます。 読み取り自体では、なにも評価しません。 Lispオブジェクトの表示表現をオブジェクトそのものに変換します。 このオブジェクトを評価すべきフォームとするか、 まったく別の目的に使うかは、readの呼び出し側で決まります。

評価とコマンドキーの解釈を混同しないでください。 エディタコマンドループは、有効なキーマップを用いて キーボード入力をコマンド(対話的に呼び出し可能な関数)に変換し、 call-interactivelyを使ってコマンドを起動します。 コマンドがLispで書いてあれば、 コマンド自体の実行には評価が関わってきますが、 そのことは、コマンドキーの解釈自体には含まれていません。

評価は再帰的な処理です。 つまり、フォームの評価では、 evalを呼び出してそのフォームの一部分を評価することもあります。 たとえば、関数呼び出しの評価においては、まず、 関数呼び出しの各引数を評価してから、関数本体の各フォームを評価します。 (car x)の評価を考えてみましょう。 まず最初にxを再帰的に評価する必要があります。 その値を関数carの引数として渡せるようにするのです。

関数呼び出しの評価においては、最終的に指定した関数を呼び出します。 See Functions。 関数の実行そのものも、関数定義を評価する場合もあります。 あるいは、関数はC言語で実装されたLisp基本関数かもしれませんし、 バイトコード関数かもしれません(see Byte Compilation)。

フォームの評価は、環境(environment)と呼ばれる文脈において 行われます。 環境とは、すべてのLisp変数の現在値と束縛です 7。 フォームが新たな束縛を作らずに変数を参照する場合には、 現在の環境におけるその変数の束縛の値を使います。 See Variables

フォームを評価すると、変数(see Local Variables)を束縛して、 再帰的評価のための新たな環境を作ることがあります。 これらの環境は一時的なもので、そのフォームの評価を完了すると 消えてしまいます。 フォームは恒久的な変更を行ってもかまいません。 このような変更を副作用(side effects)と呼びます。 副作用を持つフォームの例は、(setq foo 1)です。

フォームの各種類ごとの評価の意味の詳細は、 以下で説明します(see Forms)。


Node:Forms

フォームの種類

評価することを意図したLispオブジェクトをフォーム(form)と呼びます。 Emacsがどのようにフォームを評価するかは、そのデータ型に依存します。 Emacsには、評価方法が異なる3種類のフォームがあります。 シンボル、リスト、および、『その他すべての型』です。 本節では、3種類すべてについて1つ1つ説明します。 まず、自己評価型フォームである『その他すべての型』から説明します。


Node:Self-Evaluating Forms, Next:, Up:Forms

自己評価型フォーム

自己評価型フォーム(self-evaluating form)とは、 リストでもシンボルでもない任意のフォームのことです。 自己評価型フォームはそれ自身に評価され、 評価結果は評価されるオブジェクトと同じものです。 つまり、数25は25と評価され、 文字列"foo"は文字列"foo"と評価されます。 同様に、ベクトルを評価してもベクトルの個々の要素を評価することはありません。 その内容をまったく変更することなく、同じベクトルを返します。

'123               ; 評価していない数
     => 123
123                ; 普通どおり評価。結果は同じ
     => 123
(eval '123)        ; 『手で』評価。結果は同じ
     => 123
(eval (eval '123)) ; 2回評価してもなにも変わらない
     => 123

Lispコードにおいては、数、文字、文字列、さらにベクトルでさえも、 それらが自己評価型である事実を利用して書くのが普通です。 しかし、入力構文を持たない型については、このようにしません。 というのは、それらをテキストとして書く方法がないからです。 そのような型を含むLisp式を構成するには、Lispプログラムを使います。

;; バッファオブジェクトを含む式を作る
(setq print-exp (list 'print (current-buffer)))
     => (print #<buffer eval.texi>)
;; それを評価する
(eval print-exp)
     -| #<buffer eval.texi>
     => #<buffer eval.texi>


Node:Symbol Forms, Next:, Previous:Self-Evaluating Forms, Up:Forms

シンボルフォーム

シンボルを評価するときには、シンボルを変数として扱います。 その結果は、値があれば、変数の値です。 (値セルが空であり)値がなければ、エラーを通知します。 変数の使い方について詳しくは、See Variables

つぎの例では、setqを使ってシンボルの値を設定します。 そのあとでシンボルを評価すると、setqで保存した値を取り出せます。

(setq a 123)
     => 123
(eval 'a)
     => 123
a
     => 123

シンボルniltは特別に扱い、 nilの値はつねにnilであり、 tの値はつねにtです。 これらに別の値を設定したり、別の値を束縛することはできません。 したがって、evalはこれらを他のシンボルと同様に扱いますが、 これら2つのシンボルは自己評価型フォームのようにふるまいます。 :で始まる名前のシンボルも同じ意味で自己評価型であり、 同様に、その値を変更できません。 See Constant Variables


Node:Classifying Lists, Next:, Previous:Symbol Forms, Up:Forms

リストフォームの分類

フォームが空ではないリストならば、その最初の要素に依存して、 関数呼び出し、マクロ呼び出し、スペシャルフォームのいずれかです。 これらの3種類のフォームは、以下に説明するように、異なる方法で評価されます。 リストの残りの要素は、関数、マクロ、スペシャルフォームの 引数(arguments)になります。

空ではないリストを評価する最初の手順は、 その先頭要素を調べることです。 この要素は、それだけで、空ではないリストのフォームの種類を決定し、 リストの残りをどのように処理するかを決定します。 SchemeなどのLispの一部の方言と違って、先頭要素は評価しません


Node:Function Indirection, Next:, Previous:Classifying Lists, Up:Forms

シンボルの関数間接

リストの先頭要素がシンボルであると、 評価処理ではシンボルの関数セルを調べ、 もとのシンボルのかわりにその内容を使います。 その内容が別のシンボルであると、 シンボルの関数間接(symbol function indirection)と呼ばれる この処理をシンボルでないものを得るまで繰り返します。 シンボルの関数セルに格納された関数名としてのシンボルの使い方について 詳しくは、See Function Names

この処理の結果、無限ループになる場合もあります。 つまり、シンボルの関数セルが同じシンボルを指している場合です。 あるいは、シンボルの関数セルが空の場合もありえます。 その場合、サブルーティンsymbol-functionは、 エラーvoid-functionを通知します。 いずれの場合でもなければ、最終的にはシンボルでないものを取得し、 それは関数などの適切なオブジェクトであるはずです。

より正確にいえば、Lisp関数(ラムダ式)、バイトコード関数、 基本関数、Lispマクロ、スペシャルフォーム、自動ロードオブジェクトの いずれかを取得しているはずです。 これらの各種類ごとに、以下の1つ1つの節で説明します。 オブジェクトがこれらのいずれの型でもない場合には、 エラーinvalid-functionを通知します。

つぎの例は、シンボルの関数間接の処理を図示したものです。 fsetを使ってシンボルの関数セルに設定し、 symbol-functionを使って関数セルの内容を取り出します (see Function Cells)。 具体的には、シンボルcarfirstの関数セルに格納し、 シンボル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

一方、つぎの例では、シンボルの関数間接を使わずに関数を呼び出します。 というのは、先頭引数はLispの無名関数であって、 シンボルではないからです。

((lambda (arg) (erste arg))
 '(1 2 3))
     => 1

関数を実行することは、その本体を評価することです。 この過程では、ersteを呼び出すときにシンボルの関数間接が関わります。

組み込み関数indirect-functionは、 明示的にシンボルの関数間接を行う簡単な方法です。

indirect-function function Function
この関数は、関数としてのfunctionの意味を返す。 functionがシンボルであればfunctionの関数定義を探し、 その値から再度繰り返す。 functionがシンボルでなければfunctionそのものを返す。

Lispでindirect-functionを定義するとつぎのようになる。

(defun indirect-function (function)
  (if (symbolp function)
      (indirect-function (symbol-function function))
    function))


Node:Function Forms, Next:, Previous:Function Indirection, Up:Forms

関数フォームの評価

評価すべきリストの先頭要素が、Lisp関数オブジェクト、 バイトコードオブジェクト、基本関数オブジェクトの場合、 そのリストは関数呼び出し(function call)です。 たとえば、つぎは、関数+の呼び出しです。

(+ 1 x)

関数呼び出しを評価する最初の手順は、 リストの残りの要素を左から右へ順に評価することです。 その結果は実引数の値になり、1つの値がリストの1つの要素に対応します。 つぎの手順は、引数のリストで関数を呼び出すことで、 実質的には、関数apply(see Calling Functions)を使います。 関数がLispで書いてあれば、関数の引数変数を束縛するために引数を使います (see Lambda Expressions)。 そして、関数本体のフォーム群を順番に評価し、 本体の最後のフォームの値が関数呼び出しの値になります。


Node:Macro Forms, Next:, Previous:Function Forms, Up:Forms

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のマクロに関する完全な記述は、See Macros


Node:Special Forms, Next:, Previous:Macro Forms, Up:Forms

スペシャルフォーム

スペシャルフォーム(special form)は、 その引数を評価しないように特別な印が付いた基本関数です。 ほとんどのスペシャルフォームは、制御構造を定義したり、 変数を束縛したりします。 これらはどれも関数ではできないことです。

各スペシャルフォームには、どの引数は評価し、 どの引数は評価せずに使うかといったそれぞれに独自の規則があります。 特定の引数を評価するかどうかは、他の引数の評価結果に依存することもあります。

以下に、Emacs Lispのすべてのスペシャルフォームをアルファベット順に、 参照箇所とともにあげておきます。

and
see Combining Conditions
catch
see Catch and Throw
cond
see Conditionals
condition-case
see Handling Errors
defconst
see Defining Variables
defmacro
see Defining Macros
defun
see Defining Functions
defvar
see Defining Variables
function
see Anonymous Functions
if
see Conditionals
interactive
see Interactive Call
let
let*
see Local Variables
or
see Combining Conditions
prog1
prog2
progn
see Sequencing
quote
see Quoting
save-current-buffer
see Current Buffer
save-excursion
see Excursions
save-restriction
see Narrowing
save-window-excursion
see Window Configurations
setq
see Setting Variables
setq-default
see Creating Buffer-Local
track-mouse
see Mouse Tracking
unwind-protect
see Nonlocal Exits
while
see Iteration
with-output-to-temp-buffer
see Temporary Displays
Common Lispに関した注意: GNU Emacs LispとCommon Lispのスペシャルフォームを比較してみる。 setqif、および、catchは、Emacs Lispでも Common Lispでもスペシャルフォームである。 defunは、Emacs Lispではスペシャルフォームであるが、 Common Lispではマクロである。 save-excursionは、Emacs Lispではスペシャルフォームであるが、 Common Lispには存在しない。 throwは、Common Lispでは(複数の値を返す必要があるため) スペシャルフォームであるが、 Emacs Lispでは(複数の値はないため)関数である。


Node:Autoloading, Previous:Special Forms, Up:Forms

自動ロード

自動ロード(autoload)は、 関数やマクロの関数定義をEmacsにまだロードしていなくても、 関数やマクロを呼び出せるようにする機構です。 定義を収めたファイルを指定します。 シンボルの関数定義に自動ロードオブジェクトあるとき、 そのシンボルを関数として呼び出すと、指定したファイルを自動的にロードします。 そうしてから、当該ファイルからロードした実際の定義を呼び出します。 See Autoload


Node:Quoting

クォート

スペシャルフォームquoteは、単一の引数を 評価せずに書かれたとおりに返します。 これは、自己評価型オブジェクトではない 定数シンボルや定数リストをプログラム内に書く手段です。 (数、文字列、ベクトルなどの自己評価型オブジェクトをクォートする必要はない。)

quote object Special Form
このフォームはobjectを評価せずに返す。

quoteはプログラム内で頻繁に使うので、 Lispには便利な入力構文が用意してあります。 アポストロフ文字(')に続けた(入力構文で書いた)Lispオブジェクトは、 先頭要素がquoteであり2番目の要素がそのオブジェクトである リストに展開されます。 したがって、入力構文'xは、(quote x)の省略形です。

quoteを使った式の例をいくつかあげておきます。

(quote (+ 1 2))
     => (+ 1 2)
(quote foo)
     => foo
'foo
     => foo
''foo
     => (quote foo)
'(quote foo)
     => (quote foo)
['foo]
     => [(quote foo)]

他のクォートの書き方には、function(see Anonymous Functions)が あります。 これは、Lispで書いた無名ラムダ式をコンパイルするようにします。 また、`(see Backquote)は、 リストの一部分をクォートし、他の部分は計算結果で置き換えるために使います。


Node:Eval

評価(eval)

ほとんどの場合、実行中のプログラムにフォームが現れると フォームは自動的に評価されます。 稀なことですが、実行時に計算したフォームを評価するように コードを書く必要があるかもしれません。 たとえば、編集中のテキストからフォームを読み取ったり、 属性リストからフォームを取り出した場合などです。 このような場合には、関数evalを使います。

本節で説明した関数や変数は、フォームを評価したり、 評価処理に制限を課したり、最後の戻り値を記録したりします。 ファイルをロードしても評価が行われます(see Loading)。

注意: データ構造の中に関数を格納して それをfuncallapplyで呼び出すほうが、 データ構造の中に式を格納してそれを評価するより、 一般に明確で柔軟性があります。 関数を使うとそれらに引数として情報を渡すことができます。

eval form Function
この関数は、式を評価する基本的な関数である。 formを現在の環境において評価し、その結果を返す。 評価処理はオブジェクトの型に依存する(see Forms)。

evalは関数なので、evalの呼び出しに現れる 引数の式は2度評価される。 evalを呼び出すまえの準備で1回、 関数eval自身による評価でもう1回である。 例を示す。

(setq foo 'bar)
     => bar
(setq bar 'baz)
     => baz
;; evalは引数fooを受け取る
(eval 'foo)
     => bar
;; evalは引数barを受け取る。それはfooの値
(eval foo)
     => baz

evalの呼び出しの深さは、 max-lisp-eval-depth(下記参照)に制限される。

eval-region start end &optional stream read-function コマンド
この関数は、カレントバッファのstartendで指定した リージョン内のフォーム群を評価する。 リージョンからフォームを読み取り、 それらに対してevalを呼び出すことを リージョンの末尾に達するまで、あるいは、処理されないエラーが通知されるまで 繰り返す。

streamnil以外ならば、 リージョン内の式を評価した結果の値はstreamを使って表示する。 see Output Streams

read-functionnil以外にならば、 それは関数である必要があり、 readのかわりに式を1つ1つ読むために使われる。 この関数は、入力用のストリームである1つの引数で呼び出される。 変数load-read-function(see How Programs Do Loading)を 使ってこの関数を指定することもできるが、 引数read-functionを用いたほうが堅牢である。

eval-regionはつねにnilを返す。

eval-current-buffer &optional stream コマンド
これはeval-regionと同様だが、バッファ全体に作用する。

max-lisp-eval-depth Variable
この変数は、 (エラーメッセージ"Lisp nesting exceeds max-lisp-eval-depth"で) エラーを通知までのevalapplyfuncallの呼び出しの 最大の深さを制限する。 この制限、および、これを超えたときのエラーは、 不正に定義された関数によってLispが無限に再帰することを防止する 1つの方法である。

深さ制限は、Lispコードによる明示的な呼び出しに加えて、 Lisp式で書かれた関数の呼び出しや関数呼び出しの引数や関数本体のフォームの 再帰的な評価などの内部的なevalapplyfuncallの 呼び出しも数える。

この変数のデフォルト値は300。 これに100未満の値を設定すると、指定した値に達するとLispは100に設定し直す。 Lispデバッガに入ったとき、 制限に近い場合にはデバッガ自身が実行できることを保証するために値を増やす。

max-specpdl-sizeは、入れ子の深さを制限する別の方法である。 see Local Variables

values Variable
この変数の値は、 バッファから式を読み取り、評価し、結果を表示するEmacsの標準コマンドが行った すべての式の戻り値のリストである。 リストの順序は、最新のものが最初にくる。
(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)
;; こうすると、新たな要素が追加され、
;;   すべての要素が1つうしろへさがる
(nth 1 values)
     => (A 3 t)
;; この例を実行するまえの最新のもののつぎの要素を取得する
(nth 3 values)
     => 1


Node:Control Structures, Next:, Previous:Evaluation, Up:Top

制御構造

Lispプログラムは、式、すなわち、フォーム(forms、see Forms)から 成ります。 フォームを制御構造(control structures)で囲むことで、 フォームの実行順序を制御します。 制御構造はスペシャルフォームであり、 その内側にあるフォームの実行をいつ行うか、行わないか、 何回行うかを制御します。

もっとも単純な実行順序は逐次実行です。 最初のフォームaを実行し、 それからつぎのフォームbを実行し、といった具合です。 関数の本体やLispコードのファイルのトップレベルに複数のフォームを順に書くと、 このようになります。 つまり、書かれている順番にフォームを実行します。 これをテキスト上の順序(textual order)と呼びます。 たとえば、関数本体が2つのフォームabから成る場合、 関数を評価すると、まずaを評価し、つぎにbを評価して、 関数の値はbの値になります。

明示的な制御構造により、逐次実行以外の実行順序が可能になります。

Emacs Lispには数種類の制御構造があり、 逐次実行の変形、条件付き実行、繰り返し実行、 (制御された)ジャンプなどです。 これらすべては、以下に説明します。 組み込みの制御構造はスペシャルフォームです。 というのは、それらのサブフォームは必ずしも評価しませんし、 逐次評価するわけでもないからです。 マクロを使えば、独自の制御構造の構文を定義できます(see Macros)。


Node:Sequencing, Next:, Up:Control Structures

逐次実行

現れる順番にフォームを評価することは、 1つのフォームから別のフォームへ制御を移すもっとも一般的な方法です。 関数本体などのある種の文脈では、自動的にこのようになります。 それ以外では、これを行う制御構造の構文を使う必要があります。 prognがその制御構造で、Lispのもっとも単純な制御構造です。

スペシャルフォームprognはつぎのような形です。

(progn a b c ...)

これは、フォーム、abc、…をこの順に評価します。 これらのフォームをprognフォームの本体と呼びます。 本体の最後のフォームの値が、progn全体の値になります。

初期のころのLispでは、prognは、 2つ以上のフォームを逐次実行しそれらの最後の値を使う唯一の方法でした。 しかし、プログラマは、(当時は)1つのフォームしか許されていない 関数の本体では、 prognを使う必要がしばしばあることに気づきました。 そのため、関数本体を『暗黙のprogn』にしたのです。 つまり、実際のprognの本体のように、 複数のフォームを許すようにしたのです。 多くの他の制御構造も、同様に、暗黙のprognです。 その結果、prognは、かつてほどは多用されません。 現在では、unwind-protectandorの内側や、 ifthen部分で必要とされるのがほとんどです。

progn forms... Special Form
このスペシャルフォームは、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つの制御構造も同様にフォームを逐次評価しますが、 返す値が異なります。

prog1 form1 forms... Special Form
このスペシャルフォームは、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"

変数のリストから先頭要素を取り除き、取り除いた要素を返すにはつぎのように書く。

(prog1 (car x) (setq x (cdr x)))

prog2 form1 form2 forms... Special Form
このスペシャルフォームは、form1form2formsの フォームすべてをテキスト上の順に評価し、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"


Node:Conditionals, Next:, Previous:Sequencing, Up:Control Structures

条件付き実行

条件付き制御構造は、選択肢を選びます。 Emacs Lispには、4つの条件付きフォームがあります。 他の言語のものとほとんど同じififの変形であるwhenunless、 一般化したcase文であるcondです。

if condition then-form else-forms... Special Form
ifは、conditionをもとにして、 then-formelse-formsを選ぶ。 conditionnil以外に評価されると、 then-formを評価し、その結果を返す。 さもなければ、else-formsをテキスト上の順に評価し、 その最後のものの値を返す。 (ifelse部分は、暗黙のprognの例である。 see Sequencing。)

conditionが値nilであり、かつ、else-formsがないと、 ifnilを返す。

ifがスペシャルフォームであるのは、 選択しなかった分岐をけっして評価しないからである。 したがって、つぎの例では、 printはけっして呼ばれないためtrueは表示されない。

(if nil
    (print 'true)
  'very-false)
=> very-false

when condition then-forms... Macro
これはifの変形であり、else-formsがなく、 then-formsは複数のフォームでもよい。 特に、
(when condition a b c)

は、つぎとまったく等価である。

(if condition (progn a b c) nil)

unless condition forms... Macro
これはthen-formがないifの変形である。
(unless condition a b c)

は、つぎとまったく等価である。

(if condition nil
   a b c)

cond clause... Special Form
condは任意個数の選択肢から1つを選ぶ。 condの各節clauseはリストである必要がある。 このリストのCARcondition(条件)である。 残りの要素は、あれば、body-forms(本体フォーム)である。 つまり、各節はつぎのようになる。
(condition body-forms...)

condは、各節のconditionを評価して、 各節をテキスト上の順に試す。 conditionの値がnil以外であれば、 その節は『成功』する。 そうすると、condはその節のbody-formsを評価し、 body-formsの最後の値がcondの値となる。 残りの節は無視する。

conditionの値がnilであると、 その節は『失敗』し、 condはつぎの節へ移りそのconditionを試す。

conditionnilに評価されると、 すべての節が失敗し、condnilを返す。

clauseは、つぎの形式でもよい。

(condition)

この場合、conditionnil以外であると、 conditioncondフォームの値になる。

以下の例には4つの節があり、 xの値が、数、文字列、バッファ、シンボルかどうか調べる。

(cond ((numberp x) x)
      ((stringp x) x)
      ((bufferp x)
       (setq temporary-hack x) ; 1つの節に
       (buffer-name x))        ; 複数個の本体フォーム
      ((symbolp x) (symbol-value x)))

最後の節を除くそれよりまえの節がどれも成功しないときには、 最後の節を実行したいことがしばしばある。 これを行うには、(t body-forms)のように 最後の節のconditiontを使う。 フォームttと評価され、けっしてnilではない。 そのため、condがこの節に達したときには、 この節が失敗することはない。

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

(cond ((eq a 'hack) 'foo)
      (t "default"))
=> "default"

この式は、aの値がhackのときにはfooを返し、 さもなければ文字列"default"を返すcondである。

任意の条件付き構造は、condifで表現できます。 したがって、どちらを使うかは好みの問題です。 たとえば、つぎのとおりです。

(if a b c)
==
(cond (a b) (t c))


Node:Combining Conditions, Next:, Previous:Conditionals, Up:Control Structures

条件の組み合わせ

本節では、ifcondとともに用いて複雑な条件を表現するために しばしば使われる3つの構造を説明します。 andorの構造は、 複数の条件付き構造の一種として単独で使うこともできます。

not condition Function
この関数は、conditionが偽であるかどうか調べる。 conditionnilであればtを返し、 さもなければnilを返す。 関数notnullと同一であるが、 空リストかどうか調べる場合には、nullを使うことを勧める。

and conditions... Special Form
スペシャルフォームandは、 すべてのconditionsが真であるかどうか調べる。 conditionsを1つ1つ書かれた順に評価して調べる。

conditionsのどれかがnilに評価されると、 andの結果は、残りのconditionsに関係なく、nilになる。 つまり、andはただちに完了し、 conditionsの残りを無視する。

conditionsすべてがnil以外であることがわかると、 それらの最後の値がフォームandの値となる。

例を示そう。 最初の条件は整数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)は実行されず、 そのためエラーを回避することに注意。

andは、ifcondで表現できる。 たとえば、つぎのとおり。

(and arg1 arg2 arg3)
==
(if arg1 (if arg2 arg3))
==
(cond (arg1 (cond (arg2 arg3))))

or conditions... Special Form
スペシャルフォームorは、 conditionsの少なくとも1つが真であるかどうか調べる。 conditionsを1つ1つ書かれた順に評価して調べる。

conditionsのどれかがnil以外に評価されると、 orの結果はnil以外になる。 そして、orはただちに完了し、 conditionsの残りを無視する。 戻り値は、nil以外に評価された値である。

conditionsすべてがnilであることがわかると、 ornilを返す。

たとえば、つぎの式は、xが0かnilであることを調べる。

(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)は、 どの引数も一度だけ評価する。


Node:Iteration, Next:, Previous:Combining Conditions, Up:Control Structures

繰り返し

繰り返しとは、プログラムのある部分を何度も実行することです。 たとえば、リストの各要素や0からnの各整数について 1回ずつある計算を行いたい場合です。 Emacs Lispでこれを行うには、スペシャルフォームwhileを使います。

while condition forms... Special Form
whileは、まずconditionを評価する。 結果がnil以外であれば、formsをテキスト上の順で評価する。 そして、conditionを評価し直し、その結果がnil以外であれば、 再度formsを評価する。 この処理をconditionnilに評価されるまで繰り返す。

繰り返し回数に制限はない。 ループは、conditionnilに評価される、 エラーが発生する、throwによりループから抜け出す (see Nonlocal Exits)のいずれかが起こるまで繰り返される。

フォームwhileの値はつねにnilである。

(setq num 0)
     => 0
(while (< num 4)
  (princ (format "Iteration %d." num))
  (setq num (1+ num)))
     -| Iteration 0.
     -| Iteration 1.
     -| Iteration 2.
     -| Iteration 3.
     => nil

終了検査のまえに各繰り返しごとに実行したいことがあれば、 以下のように、それらと終了検査をprognでまとめたものを whileの第1引数にする。

(while (progn
         (forward-line 1)
         (not (looking-at "^$"))))

これは、1行先へ移動し、空行に達するまで、移動を繰り返す。 このwhileには本体がなく、 終了検査(かつポイントを実際に動かす)だけであるという点で、 風変わりである。


Node:Nonlocal Exits, Previous:Iteration, Up:Control Structures

非ローカル脱出

非ローカル脱出(nonlocal exit)とは、 プログラムのある場所から別の離れた場所へ制御を移すことです。 Emacs Lispでは、エラーの結果として非ローカル脱出が発生します。 非ローカル脱出は、明示的な制御にも使えます。 非ローカル脱出は、脱出対象の構造で作成したすべての変数束縛を解きます。


Node:Catch and Throw, Next:, Up:Nonlocal Exits

明示的な非ローカル脱出: catchthrow

ほとんどの制御構造は、その構造内での制御の流れだけに影響します。 関数throwは、通常のプログラム実行のこのような規則の例外です。 つまり、要求に従って非ローカルな脱出を行います。 (ほかにも例外はあるが、それらはエラー処理のためだけである。) throwcatchの内側で使い、 そのcatchへ戻ります。

(defun foo-outer ()
  (catch 'foo
    (foo-inner)))

(defun foo-inner ()
  ...
  (if x
      (throw 'foo t))
  ...)

フォームthrowを実行すると、対応するcatchへ制御が戻り、 そのcatchはただちに終了します。 throwに続くコードは実行されません。 throwの第2引数は、catchの戻り値として使われます。

関数throwは、その第1引数に基づいて対応するcatchを探します。 つまり、catchの第1引数が throwに指定されたものにeqであるcatchを探します。 そのようなcatchが複数個ある場合には、 もっとも内側のものを優先します。 したがって、上の例では、throwfooを指定し、 foo-outercatchは同じシンボルを指定しているので、 そのcatchを使います (ただし、これらのあいだには他の一致するcatchがないとして)。

throwの実行により、 対応するcatchまでのすべてのLispの構造を抜け出します。 これには関数呼び出しも含みます。 letや関数呼び出しなどの束縛を作る構造からもこのように抜け出すので、 通常どおり抜け出す場合と同様に束縛を解きます (see Local Variables)。 同様に、throwは、save-excursion(see Excursions)で 保存したバッファや位置情報、 save-restrictionで保存したナロイング状態、 save-window-excursion(see Window Configurations)で保存した ウィンドウの選択状態も復元します。 さらに、スペシャルフォームunwind-protectで設定した後始末を このフォームから抜け出すときに実行します(see Cleanups)。

throwは、テキスト上で、 ジャンプ先であるcatchの内側に現れる必要はありません。 throwは、catch内から呼ばれた別の関数からも戻ることもできます。 throwの実行が、 時間的にcatchに入ったあとで、かつ、それから抜けるまえである限り、 throwは対応するcatchを参照できます。 エディタコマンドループ(see Recursive Editing)から抜ける exit-recursive-editなどのコマンドで throwを使えるのは、このような理由からです。

Common Lispに関した注意: Common Lispを含むほとんどの他のLispには、 非逐次的に制御を移す方法がいくつかある。 たとえば、returnreturn-fromgo。 Emacs Lispにはthrowしかない。

catch tag body... Special Form
catchは、関数throw向けに戻り位置を確立する。 その戻り位置は、tagによって他の戻り位置と区別される。 tagは、nil以外ならば任意のLispオブジェクトでよい。 引数tagは、戻り位置を確立するまえに、通常どおり評価される。

戻り位置を確立してから、catchは、bodyのフォームを テキスト上の順に評価する。 エラーや非ローカル脱出なしにフォームの実行が普通に終了した場合、 catchは、最後の本体フォームの値を返す。

bodyの内側で、tagと同じ値を指定したthrowが実行されると、 catchはただちに終了する。 このとき返す値は、throwの第2引数に指定されたものである。

throw tag value Function
throwの目的は、 catchでまえもって確立しておいた戻り位置へ復帰することである。 引数tagは、さまざまな既存の戻り位置から選ぶために使う。 tagは、catchで指定した値とeqである必要がある。 tagに複数の戻り位置が一致する場合には、もっとも内側のものを使う。

引数valueは、対応するcatchの戻り値として使う。

タグtagである有効な戻り位置がなければ、 (tag value)を伴ったエラーno-catchを通知する。


Node:Examples of Catch, Next:, Previous:Catch and Throw, Up:Nonlocal Exits

catchthrowの例

catchthrowの使い方の1つは、 2重のループからの脱出です。 (ほとんどの言語では、これを『go to』で行うであろう。) ここでは、ijを0から9に変えながら、 (foo i j)を計算します。

(defun search-foo ()
  (catch 'loop
    (let ((i 0))
      (while (< i 10)
        (let ((j 0))
          (while (< j 10)
            (if (foo i j)
                (throw 'loop (list i j)))
            (setq j (1+ j))))
        (setq i (1+ i))))))

fooがある時点でnil以外を返すと、 ただちに止まってijのリストを返します。 fooがつねにnilを返すと、 catchは通常どおりに戻って、その値はnilです。 というのは、whileの結果はnilだからです。

2つの巧妙な例をあげましょう。 多少異なる2つの戻り位置が同時に存在します。 まず、同じタグhackで2つの戻り位置があります。

(defun catch2 (tag)
  (catch tag
    (throw 'hack 'yes)))
=> catch2

(catch 'hack
  (print (catch2 'hack))
  'no)
-| yes
=> no

どちらの戻り位置もthrowに一致するタグなので、 内側のもの、つまり、catch2で確立したものに戻ります。 したがって、catch2は値yesで通常どおり戻り、 この値が表示されます。 最後に、外側のcatchの2番目の本体フォーム、 つまり、'noが評価され、外側のcatchから戻ります。

今度は、catch2に指定する引数を変更してみます。

(defun catch2 (tag)
  (catch tag
    (throw 'hack 'yes)))
=> catch2

(catch 'hack
  (print (catch2 'quux))
  'no)
=> yes

ここでも2つの戻り位置がありますが、 今度は外側のものだけがタグhackです。 内側のものはタグquuxです。 したがって、throwにより、外側のcatchが値yesを返します。 関数printはけっして呼ばれず、 本体フォーム'noもけっして評価されません。


Node:Errors, Next:, Previous:Examples of Catch, Up:Nonlocal Exits

エラー

Emacs Lispが、なんらかの理由で評価できないフォームを評価しようとしたときには、 Emacs Lispはエラー(error)を通知(signals)します。

エラーが通知されると、Emacsのデフォルトの動作は、 エラーメッセージを表示し、現在のコマンドの実行を終了します。 バッファの末尾でC-fを打ったときなどのように、 これはほとんどの場合、適切なことです。

複雑なプログラムでは、単に終了するだけでは満足できないこともあります。 たとえば、プログラムではデータ構造に一時的な変更を加えていたり、 プログラム終了時には削除する必要がある一時的なバッファを作成するでしょう。 そのような場合には、unwind-protectを使って、 エラー発生時に評価される後始末式(cleanup expressions)を 確立しておきます。 (see Cleanups。) 場合によっては、サブルーティンでエラーが発生しても、 プログラムの実行を継続したいこともあるでしょう。 このような場合には、condition-caseを使って、 エラー状態から制御を回復するための エラーハンドラ(error handlers)を確立しておきます。

エラー処理を用いてプログラムのある場所から別の場所へ制御を移す、 という誘惑には耐えてください。 そのかわりにcatchthrowを使いましょう。 See Catch and Throw


Node:Signaling Errors, Next:, Up:Errors

エラーの通知方法

ほとんどのエラーは、他の目的で呼び出したLisp関数の内部で『自動的』に 通知されます。 整数のCARを計算しようとしたり、 バッファの末尾で1文字進めようとしたりしたときなどです。 関数errorや関数signalで、 明示的にエラーを通知することもできます。

ユーザーがC-gを打ったときに発生する中断は、 エラーとは考えませんが、エラーのように扱います。

error format-string &rest args Function
この関数は、format-stringargsformat(see String Conversion)を適用して作った エラーメッセージを伴ったエラーを通知する。

errorの典型的な使い方を以下に示す。

(error "That is an error -- try something else")
     error--> That is an error -- try something else

(error "You have committed %d errors" 10)
     error--> You have committed 10 errors

errorは、2つの引数、 エラーシンボルerrorformatが返す文字列を含むリスト でsignalを呼び出すことで動作する。

警告: 独自のエラーメッセージをそのまま使いたい場合に、 単に(error string)とは書かないこと。 string%が含まれていると、 それは書式付け指定と解釈され、予測不能な結果を招く。 そのかわりに、(error "%s" string)を使う。

signal error-symbol data Function
この関数は、error-symbolという名前のエラーを通知する。 引数dataは、エラーの状況に関連したLispオブジェクトのリストである。

引数error-symbolは、エラーシンボル(error symbol)である 必要がある。 つまり、属性error-conditionsを持つシンボルであり、 その属性値は条件名のリストである。 これにより、Emacsはエラーの異なる種類を分類する。

dataのオブジェクトの個数と重要性はerror-symbolに依存する。 たとえば、エラーwrong-type-argでは、 リストには2つのオブジェクトがあるはずで、 予期した型を表す述語とその型に一致しなかったオブジェクトである。 エラーシンボルの説明は、see Error Symbols

error-symboldataの両者は、 任意のエラーハンドラで利用できる。 condition-caseは、ローカル変数に フォーム(error-symbol . data)のリストを束縛する (see Handling Errors)。 エラーが処理されないと、これらの2つの値はエラーメッセージの表示に使われる。

関数signalはけっして戻らない (しかし、Emacsの古い版では戻る場合もある)。

(signal 'wrong-number-of-arguments '(x y))
     error--> Wrong number of arguments: x, y

(signal 'no-such-error '("My unknown error condition"))
     error--> peculiar error: "My unknown error condition"

Common Lispに関した注意: Emacsには、Common lispの継続可能なエラーの概念に相当するものはない。


Node:Processing of Errors, Next:, Previous:Signaling Errors, Up:Errors

Emacsのエラー処理方法

エラーが通知されると、signalは、 エラーに対する有効なハンドラ(handler)を探します。 ハンドラは、Lispプログラムの一部でエラーが発生した場合に 実行されるように指定されたLisp式の列です。 エラーに対して適用可能なハンドラがあると、 そのハンドラが実行され、ハンドラに続いて制御は復旧します。 ハンドラは、そのハンドラを設定したcondition-caseの環境で実行されます。 condition-caseの内側で呼び出された関数はすべて終了しているので、 ハンドラからそれらへ戻ることはできません。

エラーに適用可能なハンドラがなければ、 現在のコマンドは終了し、制御はエディタコマンドループへ戻ります。 というのは、コマンドループには、 すべての種類のエラーに対する暗黙のハンドラがあるからです。 コマンドループのハンドラは、エラーシンボルと関連するデータを使って エラーメッセージを表示します。

明示的なハンドラがないエラーは、Lispデバッガを呼び出すこともあります。 変数debug-on-error(see Error Debugging)が nil以外であると、デバッガが有効になります。 エラーハンドラと違って、デバッガはエラーの環境で実行されるので、 エラー時の変数の正確な値を調べることができます。


Node:Handling Errors, Next:, Previous:Processing of Errors, Up:Errors

エラーハンドラの書き方

エラーを通知することの普通の効果は、 実行中のコマンドを終了し、Emacsのエディタコマンドループにただちに戻ります。 読者のプログラムの一部で発生したエラーを捕捉するようにするには、 スペシャルフォームcondition-caseを使ってエラーハンドラを設定します。 単純な例はつぎのようになります。

(condition-case nil
    (delete-file filename)
  (error nil))

これはfilenameという名前のファイルを削除しますが、 エラーが発生するとどんなエラーでも捕捉してnilを返します。

condition-caseの第2引数を 保護されたフォーム(protected form)と呼びます。 (上の例では、保護されたフォームはdelete-fileの呼び出し。) このフォームの実行を開始するとエラーハンドラが有効になり、 このフォームから戻るとエラーハンドラは取り除かれます。 そのあいだは、つねにエラーハンドラは有効です。 特に、このフォームから呼び出される関数の実行中、 それらのサブルーティンの実行中などには、エラーハンドラは有効です。 これは大切なことで、厳密にいえば、 エラーが通知されるのは、保護されたフォームから呼び出された (signalerrorを含む)Lisp基本関数の実行中であって、 保護されたフォームそのものからではないからです。

保護されたフォームのうしろにある引数は、ハンドラです。 各ハンドラは1つ以上の(シンボルである)条件名 (condition names)を列挙し、処理するエラーを指定します。 エラーが通知されたときのエラーシンボルも条件名のリストを定義します。 それらに共通の条件名があるとき、 エラーハンドラがエラーに適用されます。 上の例では、1つのハンドラがあり、条件名は1つ、errorを指定しています。 この条件名はすべてのエラーを意味します。

適用可能なハンドラの探索では、 もっとも最近に確立されたハンドラから始めて、 確立されたすべてのハンドラを調べます。 したがって、フォームcondition-caseが2つ入れ子になっていて 同じ名前のハンドラを確立していると、内側のものが実際に処理を受け持ちます。

フォームcondition-caseでエラーが処理されるときには、 debug-on-errorでエラーによりデバッガを起動するように指定してあっても デバッガは実行されません。 See Error Debuggingcondition-caseで捕捉されるエラーをデバッグしたいときには、 変数debug-on-signalnil以外の値を設定します。

エラーを処理できる場合には、制御はハンドラに移ります。 こうするまえに、Emacsは、抜け出し対象となる束縛作成構造が設定した すべての変数束縛を解き、抜け出し対象となるフォームunwind-protect すべての後始末を実行します。 ハンドラに制御が移ると、ハンドラの本体を実行します。

ハンドラ本体の実行を完了すると、 フォームcondition-caseから戻ります。 ハンドラを実行するまえに保護されたフォームから完全に抜けているので、 ハンドラでは、エラー発生時点から再開したり、 保護されたフォームの内側で作られた変数束縛を調べたりすることはできません。 ハンドラでできることは、後始末をして先へ進むことだけです。

condition-case構造は、insert-file-contentsの呼び出しで ファイルのオープンに失敗するなどの予測可能なエラーを捕捉するために しばしば使われます。 プログラムがユーザーから読み取った式を評価する場合のように、 まったく予測不可能なエラーを捕捉するためにも使われます。

エラー通知とエラー処理は、throwcatchに多少似ていますが、 それらはまったく別の機能です。 catchではエラーを捕捉できませんし、 エラーハンドラではthrowを処理できません (しかしながら、適切なcatchがないthrowを使うと、 処理できるエラーを通知する)。

condition-case var protected-form handlers... Special Form
このスペシャルフォームは、protected-formの実行中は エラーハンドラhandlersを確立する。 protected-formがエラーなしに完了すると、 その戻り値がフォームcondition-caseの値になる。 この場合、condition-caseはなんの効果もない。 フォームcondition-caseで違いがでるのは、 protected-formの実行中にエラーが起こった場合である。

handlersは、(conditions body...)の形式の リストである。 ここでconditionsは、処理すべきエラーの条件名か条件名のリストである。 bodyは1つ以上のLisp式であり、 このハンドラがエラーを処理するときに実行される。 ハンドラの例を示す。

(error nil)

(arith-error (message "Division by zero"))

((arith-error file-error)
 (message
  "Either division by zero or failure to open a file"))

生起する各エラーには、 そのエラーの種類を表すエラーシンボル(error symbol)がある。 そのシンボルの属性error-conditionsは、 条件名のリストである(see Error Symbols)。 Emacsは、有効なフォームcondition-caseすべてを探索し、 これらの条件名を1つ以上指定したハンドラを探す。 もっとも内側の一致するcondition-caseがエラーを処理する。 このcondition-caseの内側では、 適用可能な最初のハンドラがエラーを処理する。

ハンドラの本体の実行を完了すると、 condition-caseは通常のように戻り、 ハンドラの本体の最後のフォームの値を全体としての値に使う。

引数varは変数である。 condition-caseは、protected-formを実行するときには この変数を束縛せず、エラーを処理するときだけ束縛する。 そのとき、varはローカルにエラー記述 (error description)に束縛される。 これは、エラーの詳細を与えるリストである。 エラー記述は、(error-symbol . data)の形式である。 ハンドラは、動作を決定するためにこのリストを参照できる。 たとえば、ファイルのオープンに失敗したエラーであれば、 dataの第2要素、エラー記述の第3要素がファイル名である。

varnilであると、変数を束縛しなことを意味する。 そうすると、ハンドラではエラーシンボルと関連するデータを使えない。

error-message-string error-description Function
この関数は、指定したエラー記述に対するエラーメッセージ文字列を返す。 エラーに対する普通のエラーメッセージを表示して、 エラーを処理したい場合に便利である。

ゼロ除算の結果であるエラーを処理するcondition-caseの使用例を示します。 ハンドラはエラーメッセージを(ベルを鳴らさずに)表示して、 大きな数を返します。

(defun safe-divide (dividend divisor)
  (condition-case err
      ;; 保護されたフォーム
      (/ dividend divisor)
    ;; ハンドラ
    (arith-error                        ; 条件
     ;; このエラーに対する普通のメッセージを表示する
     (message "%s" (error-message-string err))
     1000000)))
=> safe-divide

(safe-divide 5 0)
     -| Arithmetic error: (arith-error)
=> 1000000

ハンドラは条件名arith-errorを指定しているので、 ゼロ除算エラーだけを処理します。 少なくともこのcondition-caseでは他の種類のエラーは処理しません。 したがって、つぎのようになります

(safe-divide nil 3)
     error--> Wrong type argument: number-or-marker-p, nil

以下は、errorで通知されるエラーも含めて、 すべての種類のエラーを捕捉するcondition-caseです。

(setq baz 34)
     => 34

(condition-case err
    (if (eq baz 35)
        t
      ;; これは関数errorの呼び出し
      (error "Rats!  The variable %s was %s, not 35" 'baz baz))
  ;; これはハンドラ。フォームではない
  (error (princ (format "The error was: %s" err))
         2))
-| The error was: (error "Rats!  The variable baz was 34, not 35")
=> 2


Node:Error Symbols, Previous:Handling Errors, Up:Errors

エラーシンボルと条件名

エラーを通知するときには、読者が意図するエラーの種類を指定する エラーシンボル(error symbol)を指定します。 各エラーには、それを分類する一意な名前があります。 これは、Emacs Lisp言語で定義されたエラーを細分類したものです。

これらの細分類は、エラー条件(error conditions)と呼ばれる より大きなクラスの階層にまとめられています。 エラー条件は、条件名(condition names)で識別します。 もっとも細かい分類は、エラーシンボルそのものです。 各エラーシンボルは条件名でもあります。 より大きなクラスを表す条件名errorもあります。 これはすべての種類のエラーを表します。 したがって、各エラーには、1つ以上の条件名があります。 つまり、errorerrorとは別のエラーシンボル、あるいは、 その中間の分類に属するものです。

あるシンボルがエラーシンボルであるためには、そのシンボルには、 条件名のリストを与える属性error-conditionsがあることが必要です。 このリストは、そのエラーが属するエラー条件を定義します。 (エラーシンボルそのものと、シンボルerrorは、 つねにこのリストの要素であること。) したがって、条件名の階層は、 エラーシンボルの属性error-conditionsで定義されます。

error-conditionsリストに加えて、 エラーシンボルには、属性error-messageも必要です。 この属性の値は、そのエラーが処理されないときに表示される文字列です。 属性error-messageがあるのに、それが文字列でなければ、 エラーメッセージpeculiar errorを使います。

以下に、新たなエラーシンボルnew-errorの定義方法を示します。

(put 'new-error
     'error-conditions
     '(error my-own-errors new-error))
=> (error my-own-errors new-error)
(put 'new-error 'error-message "A new error")
=> "A new error"

このエラーには、3つの条件名があります。 もっとも細かい分類であるnew-error、 それより大きな分類とであると考えているmy-own-error、 もっとも大きな分類であるerrorです。

エラー文字列は大文字で始めるべきですが、ピリオドで終えません。 これは、Emacsの他の慣習と整合をとるためです。

普通、Emacs自身がnew-errorを通知することはありえません。 つぎのように、読者のコードで明示的に signal(see Signaling Errors)を呼んだときだけです。

(signal 'new-error '(x y))
     error--> A new error: x, y

このエラーは、3つの条件名のどれでも処理できます。 つぎの例は、new-errorと クラスmy-own-errorsの任意の他のエラーを処理します。

(condition-case foo
    (bar nil t)
  (my-own-errors nil))

エラーを分類する重要な方法は、それらの条件名によることです。 つまり、エラーに一致するハンドラを探すために条件名を使います。 エラーシンボルは、意図したエラーメッセージと条件名のリストを指定する 簡便な方法を提供するだけです。 signalに、1つのエラーシンボルではなく、 条件名のリストを指定するのではわずらわしいでしょう。

一方、条件名なしにエラーシンボルだけを使うのでは、 condition-caseの能力をいちじるしく損ないます。 条件名があることで、エラーハンドラを書くときにさまざまなレベルに 一般化してエラーを分類できるのです。 エラーシンボルだけを使ったのでは、 最細分類以外のレベルを削除してしまうことになります。

すべての標準エラー名とそれらの条件名については、 See Standard Errors


Node:Cleanups, Previous:Errors, Up:Nonlocal Exits

非ローカル脱出時の後始末

unwind-protect構造は、データ構造を一時的に整合性のない状態に するときには本質的です。 この構造により、エラーや非ローカル脱出が起こったときに、 データの整合性を回復できます。

unwind-protect body cleanup-forms... Special Form
unwind-protectは、bodyからどのように制御が離れた場合にも cleanup-formsの実行を保証して、bodyを実行する。 bodyは通常どおり完了するか、 throwを実行してunwind-protectから脱出するか、 エラーを引き起こす。 いずれの場合でも、cleanup-formsは評価される。

フォームbodyが正常に終了すると、 unwind-protectは、cleanup-formsを評価したあとに、 フォームbodyの最後の値を返す。 フォームbodyが完了しなかった場合、 unwind-protectは普通の意味での値は返さない。

unwind-protectが保護するのはbodyだけである。 cleanup-formsそのもののどれかが(throwやエラーで) 非ローカル脱出を行うと、unwind-protectは、 cleanup-formsの残りを評価することを保証しないcleanup-formsのどれかが失敗するとトラブルになる危険性がある場合には、 cleanup-formsを別のunwind-protectで保護する。

フォームunwind-protectの現在の入れ子の個数は、 ローカル変数束縛の個数とともに数えられ、 max-specpdl-sizeに制限されている(see Local Variables)。

たとえば、表示しないバッファを一時的に作成し、 終了前に確実にそれを消去したいとしましょう。

(save-excursion
  (let ((buffer (get-buffer-create " *temp*")))
    (set-buffer buffer)
    (unwind-protect
        body
      (kill-buffer buffer))))

変数bufferを使わずに(kill-buffer (current-buffer))と 書くだけで十分だと考えるかもしれません。 しかし、別のバッファに切り替えたあとでbodyでエラーが発生した場合には、 上の方法はより安全です。 (あるいは、bodyの周りに別のsave-excursionを書いて、 一時バッファを消去するときに、それがカレントバッファになることを 保証する。)

Emacsには、上のようなコードに展開されるwith-temp-bufferという 標準マクロがあります(see Current Buffer)。 本書で定義しているマクロのいくつかでは、 このようにunwind-protectを使っています。

ファイルftp.elから持ってきた実際の例を示しましょう。 リモートの計算機への接続を確立するプロセス(see Processes)を作ります。 関数ftp-loginは、その関数の作成者が予想できないほどの 数多くの問題に対してとても敏感ですから、 失敗したときにプロセスを消去することを保証するフォームで保護します。 さもないと、Emacsは、無用なサブプロセスで満たされてしまいます。

(let ((win nil))
  (unwind-protect
      (progn
        (setq process (ftp-setup-buffer host file))
        (if (setq win (ftp-login process host user password))
            (message "Logged in")
          (error "Ftp login failed")))
    (or win (and process (delete-process process)))))

この例には、小さなバグが1つあります。 ユーザーがC-gを打って中断しようとして、かつ、 関数ftp-setup-bufferの終了後に 変数processを設定するまえに実際に中断が行われると、 プロセスは消去されません。 このバグを直す簡単な方法はありませんが、 少なくとも、ほとんど起こりえません。


Node:Variables, Next:, Previous:Control Structures, Up:Top

変数

変数(variable)は、プログラムにおいて値を表すために使う名前です。 ほとんどすべてのプログラム言語には、ある種の変数があります。 Lispプログラムのテキストでは、シンボルの構文を使って変数を書きます。

ほとんどのプログラム言語と違って、Lispでは、 プログラムはLispオブジェクトで表現し、テキスト表現は副次的なものです。 変数として使うLispオブジェクトはシンボルです。 シンボル名が変数名であり、変数の値はシンボルの値セルに格納されています。 変数としてのシンボルの使い方は、関数名としての使い方とは独立しています。 See Symbol Components

Lispプログラムを構成するLispオブジェクト群は、 プログラムのテキスト表現を決定します。 つまり、Lispオブジェクト群に対する単なる入力構文です。 これは、たとえば、Lispプログラムのテキスト表現では、 変数を表現するシンボルの入力構文で変数を書く理由です。


Node:Global Variables, Next:, Up:Variables

グローバル変数

変数を使うもっとも簡単な方法は、 グローバルに(globally、大局的に)使うことです。 つまり、どんなときにも変数にはたった1つの値だけがあり、 (少なくともここでは)Lispシステム全体にその値が有効になります。 新たな値を設定するまで、その値が有効であり続けます。 新たな値で古い値を置き換えると、変数には古い値の痕跡はなにも残りません。

シンボルの値はsetqで指定します。 たとえば、

(setq x '(a b))

は、変数xに値(a b)を与えます。 setqは、最初の引数、つまり、変数の名前を評価せず、 新しい値である第2引数を評価することに注意してください。

変数にいったん値を与えれば、 式としてシンボルそのものを使うことによりその値を参照できます。 つまり、つぎのとおりです。

x => (a b)

ただし、上に示したフォームsetqを実行してあると仮定します。

同じ変数に値を設定し直すと、 新しい値で古い値を置き換えます。

x
     => (a b)
(setq x 4)
     => 4
x
     => 4


Node:Constant Variables, Next:, Previous:Global Variables, Up:Variables

変更不可能な変数

Emacs Lispには、通常それ自身に評価されるある種のシンボルがあります。 :で始まる名前の任意の変数、および、niltです。 これらのシンボルを再束縛することはできず、 それらの値を変更することもできません。 niltを設定しようとしたり束縛しようとすると、 エラーsetting-constantを通知します。 :で始まる名前のシンボルに関してもそうですが、 そのようなシンボルにそれ自身を設定することはできます。

nil == 'nil
     => nil
(setq nil 500)
error--> Attempt to set constant symbol: nil

keyword-symbols-constant-flag Variable
この変数がnilであると、 :で始まる名前の変数を望みの値に設定したり束縛したりできる。 これは、そのようなことを行う古いLispプログラムの実行を可能にするためである。


Node:Local Variables, Next:, Previous:Constant Variables, Up:Variables

ローカル変数

グローバル変数は、 明示的に新しい値で置き換えない限り存続する値を持ちます。 一時的にしか存在しない変数値、 つまり、プログラムのある部分を完了するまでのみ存在する変数値を 作れると便利なことがあります。 このような値をローカル(local、局所的)と呼び、 そのように使われる変数をローカル変数(local variables)と呼びます。

たとえば、関数を呼び出したとき、その引数変数は、 関数を抜けるまで存続する新たなローカルな値を受け取ります。 スペシャルフォームletは、指定した変数の新たなローカル値を 明示的に確立します。 これらはフォームletを抜けるまで存続します。

ローカル値を確立すると、 変数の以前の値(あるいは値がないこと)を保存します。 ローカル値の存続期間が終了すると、以前の値を復元します。 この期間は、以前の値を隠して(shadowed)いて 以前の値は見えません。 グローバル値でもローカル値でも隠せます(see Scope)。

変数がローカルなときに(setqなどで)その変数を設定すると、 ローカル値を置き換えます。 隠されているグローバル値や以前のローカル値を変更しません。 このふるまいをモデル化するために、 変数のローカル値に加えて変数のローカル束縛(local binding)を 考えます。

ローカル束縛とは、ローカル値を保持する概念的な場所です。 関数やletなどのスペシャルフォームに入るたびに ローカル束縛を作成します。 関数やフォームletから抜けるとローカル束縛を削除します。 ローカル束縛が存続する限り、変数の値はそこに保持されています。 ローカル束縛が存在するときにsetqsetを使うと、 ローカル束縛の中に別の値を格納します。 新たな束縛を作るのではありません。

グローバル値を保持する概念的な場所を グローバル束縛(global binding)ともいいます。

変数には一度に複数のローカル束縛がありえます (たとえば、同じ変数を束縛する入れ子になったフォームletがあるとき)。 そのような場合、既存のもっとも最近に作成されたローカル束縛が、 変数の現在の束縛(current binding)です。 (この規則を動的スコープ(dynamic scoping)と呼びます。 see Variable Scoping) ローカル束縛がまったくなければ、変数のグローバル束縛が現在の束縛です。 現在の束縛のことを強調して既存の最ローカル束縛と呼ぶこともあります。 シンボルの通常の評価では、その現在の束縛の値を返します。

スペシャルフォームletlet*は、 ローカル束縛を作るためにあります。

let (bindings...) forms... Special Form
このスペシャルフォームは、bindingsに従って変数を束縛し、 formsのすべてをテキスト上の順に評価する。 letフォームは、formsの最後のフォームの値を返す。

bindingsのおのおのは、(i)シンボルであるか、 (ii)フォーム(symbol value-form)のリストである。 前者は、シンボルにnilを束縛する。 後者は、symbolvalue-formの評価結果を束縛する。 value-formを省略するとnilを使う。

bindingsvalue-form群すべてを現れる順に評価してから、 シンボルにそれらの値を束縛する。 例をつぎに示す。 Zは、Yの古い値2に束縛され、Yの新しい値1ではない。

(setq Y 2)
     => 2
(let ((Y 1)
      (Z Y))
  (list Y Z))
     => (1 2)

let* (bindings...) forms... Special Form
このスペシャルフォームはletに似ているが、 変数のローカル値を計算し終えた直後にその変数を束縛し、 つぎの変数のローカル値の計算に進む。 したがって、bindings内の式では、このlet*フォーム内で まえにあるシンボルを参照できる。 つぎの例を上のletの例と比較してほしい。
(setq Y 2)
     => 2
(let* ((Y 1)
       (Z Y))    ; 設定し終えたばかりのYの値を使う
  (list Y Z))
     => (1 1)

以下にローカル束縛を作成するその他の機能の完全な一覧をあげておきます。

変数は、バッファローカルな束縛(see Buffer-Local Variablesや フレームローカルな束縛(see Frame-Local Variables)を持つことができます。 少数の変数は、端末にローカルな束縛(see Multiple Displays) を持つこともできます。 この種の束縛は普通のローカル束縛と同じように働きますが、 これらはEmacsの『どの部分』にいるかに依存したローカル化であり、 時間的なローカル化ではありません。

max-specpdl-size Variable
この変数は、("Variable binding depth exceeds max-specpdl-size"を 伴った)エラーを通知するまでに許される、 ローカル変数束縛と unwind-protectによる後始末(see Nonlocal Exits)の 全体の個数の制限を定義する。

この制限、および、これを超えたときのエラーは、 不正に定義された関数によってLispが無限に再帰することを防止する 1つの方法である。

デフォルト値は600である。 Lispデバッガに入ったとき、 制限に近い場合にはデバッガ自身が実行できることを保証するために値を増やす。


Node:Void Variables, Next:, Previous:Local Variables, Up:Variables

変数が『空』であるとき

シンボルにグローバル変数としての値を一度も与えていないとき、 そのシンボルのグローバル値は(void)であるといいます。 いいかえれば、シンボルの値セルにはどんなLispオブジェクトも入っていません。 シンボルを評価しようとすると、値ではなくエラーvoid-variableを得ます。

nilという値は空とは異なることに注意してください。 シンボルnilはLispオブジェクトであり、他のオブジェクトと同様に 変数の値になりえます。 それはなのです。 空な変数はいかなる値も持たないのです。

変数に値を与えたあとでは、makunboundを使って 再度その変数を空にできます。

makunbound symbol Function
この関数は、symbolの現在の変数束縛を空にする。 これ以降に変数としてこのシンボルの値を使おうとすると、 再度設定していない限り、エラーvoid-variableを通知する。

makunboundsymbolを返す。

(makunbound 'x)      ; 変数xのグローバル値を空にする
     => x
x
error--> Symbol's value as variable is void: x

symbolがローカルに束縛されていると、 makunboundは既存の最ローカル束縛に作用する。 ローカル束縛を作成するすべての構文は変数に値を与えるため、 これはシンボルのローカル束縛を空にする唯一の方法である。 この場面では、空の状態は、束縛が存在する限り存続する。 束縛を作成した構造から抜け出して束縛が削除されると、 通常どおりそれ以前のローカル束縛かグローバル束縛が有効になり、 その束縛が空でなければ変数は空ではない。

(setq x 1)               ; グローバル束縛に値を入れる
     => 1
(let ((x 2))             ; ローカルに束縛する
  (makunbound 'x)        ; ローカル束縛を空にする
  x)
error--> Symbol's value as variable is void: x
x                        ; グローバル束縛は変更されていない
     => 1

(let ((x 2))             ; ローカルに束縛する
  (let ((x 3))           ; もう一度
    (makunbound 'x)      ; もっとも内側のローカル束縛を空にする
    x))                  ; 参照するが、それは空
error--> Symbol's value as variable is void: x

(let ((x 2))
  (let ((x 3))
    (makunbound 'x))     ; 内側の束縛を空にし、それを削除する
  x)                     ; 外側のletの束縛が見える
     => 2

makunboundで空にした変数は、 一度も値を受け取ったことがなく、そのために空である変数と区別できません。

変数が現在、空であるかどうかは関数boundpを使って調べられます。

boundp variable Function
boundpは、(シンボル)variableが空でなければ、 より正確にいえば、現在の束縛が空でなければtを返す。 さもなければnilを返す。
(boundp 'abracadabra)          ; 空で始める
     => nil
(let ((abracadabra 5))         ; ローカルに束縛する
  (boundp 'abracadabra))
     => t
(boundp 'abracadabra)          ; グローバルにはまだ空である
     => nil
(setq abracadabra 5)           ; グローバルに空でなくする
     => 5
(boundp 'abracadabra)
     => t


Node:Defining Variables, Next:, Previous:Void Variables, Up:Variables

グローバル変数を定義する

スペシャルフォームdefconstdefvar変数定義を使って、 シンボルをグローバル変数として使う意図を表明できます。

Emacs Lispでは、定義には3つの目的があります。 まず、コードを読む人向けに、特定のシンボルを(変数として)特定目的に 使う意図があることを知らせます。 第2に、Lispシステムに対しては、値と説明文字列を提供して これらのことを伝えます。 第3に、プログラム内の関数や変数のデータベースを作成する etagsmake-docfileなどのユーティリティに情報を提供します。

defconstdefvarの違いは、主に好みの問題であり、 値が変更されるかどうかを人に伝えます。 Emacs Lispは、defconstdefvarの宣言に基づいて 変数の使い方を制限することはしません。 しかしながら、初期化に関しては違いがあります。 defconstは無条件に変数を初期化しますが、 defvarは変数が空である場合にのみ初期化します。

defvar symbol [value [doc-string]] Special Form
このスペシャルフォームは、symbolを変数として定義し、 初期値や説明文字列を設定する。 この定義は、コードを読む人向けに、 値を設定したり変更する変数としてsymbolを使うことを伝える。 symbolは評価されないことに注意。 定義するシンボルは、defvarに明示的に現れる必要がある。

symbolの値が空でありvalueを指定してあると、 defvarvalueを評価し、その結果をsymbolに設定する。 しかし、symbolにすでに値があれば(つまり、空でなければ)、 valueをまったく評価せず、symbolの値も変更しない。 valueを省略した場合、symbolの値をいっさい変更しない。

symbolにカレントバッファでバッファローカルな束縛がある場合には、 defvarはデフォルト値に作用する。 それは、バッファには独立であり、現在の(バッファローカルな)束縛ではない。 defvarは、デフォルト値が空の場合にデフォルト値を設定する。 see Buffer-Local Variables

emacs-lispモードにおいてC-M-xeval-defun)でトップレベルの フォームdefvarを評価すると、 eval-defunの特別な機能により、 変数の値が空かどうかを調べずに無条件に変数に設定する。

doc-stringがあれば、それは変数の説明文を指定する。 (説明文を指定できるのは、変数定義の主な利点の1つである。) 説明文はシンボルの属性variable-documentationに格納する。 Emacsのヘルプ関数(see Documentation)は、この属性を調べる。

doc-stringの最初の文字が*であると、 この変数をユーザーオプションと考えることを意味する。 これにより、ユーザーはコマンドset-variableedit-optionsを 使って簡単に変数を設定できる。 しかしながら、ユーザーオプションの変数には、 defvarではなくdefcustomを使ったほうがよく、 そうすればカスタマイズ情報を指定できる。 see Customization

いくつか例をあげる。 つぎのフォームはfooを定義するが初期化はしない。

(defvar foo)
     => foo

つぎの例は、barの値を23に初期化し、説明文字列を与える。

(defvar bar 23
  "The normal weight of a bar.")
     => bar

つぎの例は、barの説明文字列を変更し、 この変数をユーザーオプションにする。 しかし、barにはすでに値が設定してあるので、 その値は変更しない。 (さらに(1+ nil)は評価するとエラーになるが、 評価されないのでエラーはない。)

(defvar bar (1+ nil)
  "*The normal weight of a bar.")
     => bar
bar
     => 23

つぎの例は、スペシャルフォームdefvarに等価な式である。

(defvar symbol value doc-string)
==
(progn
  (if (not (boundp 'symbol))
      (setq symbol value))
  (if 'doc-string
    (put 'symbol 'variable-documentation 'doc-string))
  'symbol)

フォームdefvarsymbolを返すが、 通常このフォームはファイルのトップレベルで使われ、そこでは値は関係ない。

defconst symbol [value [doc-string]] Special Form
このスペシャルフォームは、symbolを変数として定義し初期化する。 この定義は、コードを読む人向けに、 symbolはこれ以降標準のグローバル値を持ち、 ユーザーや他のプログラムが変更すべきでないことを伝える。 symbolは評価されないことに注意。 定義するシンボルは、defconstに明示的に現れる必要がある。

defconstは、valueがあればつねにvalueを評価し、 その結果をsymbolに設定する。 symbolにカレントバッファのバッファローカルな束縛がある場合には、 defconstはデフォルト値を設定し、 バッファローカルな値にではない。 (しかし、defconstで定義するシンボルには、 バッファローカルな束縛を作るべきではない。)

つぎの例では、piは、(インディアナ州立法府はいうにおよばず) だれも変更すべきではないと考えられる定数である。 しかし、2番目のフォームからわかるように、これは単に助言でしかない。

(defconst pi 3.1415 "Pi to five places.")
     => pi
(setq pi 3)
     => pi
pi
     => 3

user-variable-p variable Function
この関数は、variableがユーザーオプション、つまり、 カスタマイズのためにユーザーが設定することを意図した変数であると、 tを返し、さもなければnilを返す。 (ユーザーオプション向け以外の変数は、Lispプログラムの内部目的用にあり、 それらについてユーザーが知る必要はない。)

ユーザーオプション変数は、 属性variable-documentationの最初の文字で他の変数と区別される。 その属性が存在して文字列であり、最初の文字が*であれば、 その変数はユーザーオプションである。

ユーザーオプション変数に属性variable-interactiveがあると、 コマンドset-variableはその属性値を使って、 変数の新しい値の読み取りを制御します。 この属性値は、interactiveの引数(see Using Interactive) のように使われます。 しかしながら、この機能はdefcustom(see Customization)により ほとんど廃れています。

警告: 変数にローカル束縛があるときに スペシャルフォームdefconstdefvarを使うと、 ローカル束縛の値を変更し、グローバル束縛は変更しない。 これは望む効果ではない。 これを防ぐには、これらのスペシャルフォームはファイルのトップレベルで使う。 そうすれば、普通は有効なローカル束縛はない。 さらに、変数のローカル束縛を作るまえに、 確実にファイルをロードしておく。


Node:Tips for Defining, Next:, Previous:Defining Variables, Up:Variables

変数を堅牢に定義するためのヒント

(内部に束縛を含むようなキーマップなどの)複雑な値を保持する変数を 定義し初期化するときには、つぎのように、 値の計算全体をdefvarの内部に入れておくのが最良です。

(defvar my-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map "\C-c\C-a" 'my-command)
    ...
    map)
  docstring)

この方法には、いくつかの利点があります。 まず、ファイルのロード中にユーザーが中断した場合、 変数は初期化されないか正しく初期化されるかのいずれかであり、 その中間状態ということはありません。 第2に、変数をすでに初期化したあとにファイルをロードし直しても、 変数を変更しません。 (キーをバインドし直すなどの)内容の一部を変更するために ユーザーがフックを実行した場合などには、これは重要です。 第3に、C-M-xでフォームdefvarを評価すると、 マップを完全に初期化し直せます

フォームdefvarの内側に多くのコードを置くことには、欠点が1つあります。 変数の名前を指定した行から説明文字列が離れすぎてしまうことです。 つぎのようにしてこれを安全に防げます。

(defvar my-mode-map nil
  docstring)
(if my-mode-map
    nil
  (let ((map (make-sparse-keymap)))
    (define-key my-mode-map "\C-c\C-a" 'my-command)
    ...
    (setq my-mode-map map)))

これには、defvarの内側に初期化を入れたときと同じ利点がありますが、 変数を再初期化するには、各フォームそれぞれについて C-M-xを打つ必要があります。

しかし、つぎのようなコードは書かないでください。

(defvar my-mode-map nil
  docstring)
(if my-mode-map
    nil
  (setq my-mode-map (make-sparse-keymap))
  (define-key my-mode-map "\C-c\C-a" 'my-command)
  ...)

このコードでは、変数を設定してから変更しますが、 それを複数の手順で行います。 setqの直後にユーザーが中断すると、 変数は正しく初期化されておらず、空でもnilでもありません。 こうなったときにファイルを再ロードしても変数を初期化できません。 変数は不完全な状態のままです。


Node:Accessing Variables, Next:, Previous:Tips for Defining, Up:Variables

変数値の参照

変数を参照する普通の方法は、 変数を指名するシンボルを書くことです(see Symbol Forms)。 これには、プログラムを書くときに変数名を指定する必要があります。 読者は、普通このようにするでしょう。 場合によっては、実行時にどの変数を参照するか選ぶ必要があり、 そのときにはsymbol-valueを使います。

symbol-value symbol Function
この関数はsymbolの値を返す。 これは、シンボルのもっとも内側のローカル束縛の値、あるいは、 ローカル束縛がなければグローバル値である。
(setq abracadabra 5)
     => 5
(setq foo 9)
     => 9

;; ここで、abracadabraは、
;;   その値を調べるシンボル
(let ((abracadabra 'foo))
  (symbol-value 'abracadabra))
     => foo

;; ここで、abracadabraの値、
;;   つまりfooが、
;;   その値を調べるシンボル
(let ((abracadabra 'foo))
  (symbol-value abracadabra))
     => 9

(symbol-value 'abracadabra)
     => 5

symbolの現在の束縛が空であると、 エラーvoid-variableを通知する。


Node:Setting Variables, Next:, Previous:Accessing Variables, Up:Variables

変数値の変更

変数の値を変更する普通の方法は、スペシャルフォームsetqを使うことです。 実行時に選択する変数を計算する必要があるときには、 関数setを使います。

setq [symbol form]... Special Form
このスペシャルフォームは、変数の値を変更するもっとも一般的な方法である。 各symbolに、対応するformの評価結果である新たな値を与える。 シンボルの既存の際、ローカルの束縛を変更する。

setqsymbolを評価しない。 読者が書いたシンボルに設定する。 この変数は自動的にクォートされるのである。 setqqは、『quoted(クォートする)』を表す。

フォームsetqの値は、最後のformの値である。

(setq x (1+ 2))
     => 3
x                   ; xはグローバル値を持つ
     => 3
(let ((x 5))
  (setq x 6)        ; xのローカル束縛を設定する
  x)
     => 6
x                   ; グローバル値は変更されない
     => 3

最初のformを評価して最初のsymbolに設定し、 つぎに、2番目のformを評価して2番目のsymbolに設定し、 といった具合になることに注意。

(setq x 10          ; xは、yの値を計算するまえに
      y (1+ x))     ;   設定されることに注意
     => 11

set symbol value Function
この関数は、symbolの値としてvalueを設定し、valueを返す。 setは関数なので、symbolとして書いた式は、 設定するシンボルを得るために評価される。

変数の既存の最ローカルの束縛に設定する。 隠されている束縛には影響しない。

(set one 1)
error--> Symbol's value as variable is void: one
(set 'one 1)
     => 1
(set 'two 'one)
     => one
(set two 2)         ; twoはシンボルoneに評価される
     => 2
one                 ; そのため、oneに設定される
     => 2
(let ((one 1))      ; oneのこの束縛が設定され、
  (set 'one 3)      ;   グローバル値は設定されない
  one)
     => 3
one
     => 2

symbol(の評価結果)が実際にはシンボルでないと、 エラーwrong-type-argumentを通知する。

(set '(x y) 'z)
error--> Wrong type argument: symbolp, (x y)

論理的には、setsetqよりもさらに基本的な操作である。 どんなsetqの使い方でも、setで素直に書き直せる。 setqは、setを使ってマクロとして定義することも可能である。 しかし、setそのものを使うことは稀であり、 初心者はsetを知る必要がほとんどない。 設定する変数を実行時に選ぶときにのみ有用である。 たとえば、コマンドset-variableは、 ユーザーから変数名を読み取りその変数に設定するので、 setを使う必要がある。

Common Lispに関した注意: Common Lispでは、setはつねにシンボルの『スペシャル』な、つまり、 動的な値を変更し、文脈上の束縛を無視する。 Emacs Lispでは、すべての変数とすべての束縛は動的であり、 setはつねに既存の最ローカルの束縛に作用する。

変数に設定する別の関数は、リストに既存でない要素を追加するように 設計されたものです。

add-to-list symbol element Function
この関数は、elementが変数symbolの値のリストのメンバでなければ、 elementと変数symbolの値をコンスした値を 変数symbolに設定する。 リストを変更してもしなくても結果のリストを返す。 呼び出すまえに、symbolの値はリストであるほうがよい。

引数symbolは暗黙にクォートされない。 add-to-listは、setのように普通の関数であり、 setqとは違う。 必要ならば、読者自身でクォートする。

add-to-listの使い方を以下に示します。

(setq foo '(a b))
     => (a b)

(add-to-list 'foo 'c)     ;; cを追加する
     => (c a b)

(add-to-list 'foo 'b)     ;; なんの効果もない
     => (c a b)

foo                       ;; fooは変更されている
     => (c a b)

(add-to-list 'var value)に等価な式はつぎのとおりです。

(or (member value var)
    (setq var (cons value var)))


Node:Variable Scoping, Next:, Previous:Setting Variables, Up:Variables

変数束縛のスコープルール

あるシンボルfooは、さまざまなローカルな変数束縛を持つことができます。 Lispプログラムの異なる場所で確立されたものや グローバル束縛です。 もっとも最近に確立した束縛が他のものに優先します。

Emacs Lispのローカル束縛は、無限のスコープ(indefinite scope)と 動的存続期間(dynamic extent)を持ちます。 スコープ(scope)とは、ソースコードのテキスト上の どこから束縛を参照できるかを表します。 無限のスコープとは、プログラムのどこからでも変数束縛を参照できることを 意味します。 存続期間(extent)とは、プログラムの実行にしたがって、 いつ束縛が存在するかを表します。 動的存続期間とは、束縛を作成した構造が有効である限り、 束縛が存続することを意味します。

動的存続期間と無限のスコープの組み合せを 動的スコープ(dynamic scoping)と呼びます。 対照的に、ほとんどのプログラム言語は、 レキシカルスコープ(lexical scoping)を用います。 つまり、ローカル変数の参照は、 その変数を束縛する関数やブロックのテキスト上で内側にある必要があります。

Common Lispに関した注意: Common Lispでは、『スペシャル』と宣言した変数は、 Emacs Lispのすべての変数と同様に、動的スコープである。


Node:Scope, Next:, Up:Variable Scoping

スコープ

Emacs Lispでは、 ローカル変数束縛は無限のスコープ(indefinite scope)です。 つまり、プログラムテキスト上のどの関数からでも、 ある変数束縛を参照できるのです。 つぎの関数定義を考えてみましょう。

(defun binder (x)   ; xは、binderで束縛
   (foo 5))         ; fooは別の関数

(defun user ()      ; xは、userにおいて『自由』
  (list x))

テキスト上のスコープを用いる言語では、 binder内のxの束縛を、userで参照することはできません。 なぜなら、userは、テキスト上で関数binderの内側にはないからです。 しかしながら、動的スコープのEmacs Lispでは、 状況に応じて、binder内で確立したxの束縛を userから参照してもしなくてもよいのです。

Emacs Lispで動的スコープを使うのは、 テキスト上のスコープの単純な実装は遅いからです。 さらに、すべてのLispシステムは、少なくともオプションとして、 動的スコープを使えるようにする必要があります。 テキスト上のスコープが標準であると、 特定の変数に対して動的スコープを指定する方法が必要になります。 Emacsで両方のスコープを使えるようにしてもよいのですが、 動的スコープだけだと実装がより簡単になります。


Node:Extent, Next:, Previous:Scope, Up:Variable Scoping

存続期間

存続期間(Extent)とは、プログラムの実行中において、 変数名が有効である期間を指します。 Emacs Lispでは、束縛を作ったフォームを実行している期間中だけ、 変数は有効です。 これを動的存続期間(dynamic extent)と呼びます。 CやPascalなどのほとんどの言語の『ローカル』変数や『自動』変数も 動的存続期間です。

動的存続期間とは別のものに無限の存続期間(indefinite extent)があります。 つまり、変数束縛は、その束縛を作ったフォームから抜けても存続するのです。 たとえば、Common LispやSchemeにはこれがありますが、Emacs Lispにはありません。

これを説明するために、つぎの関数make-addを考えます。 この関数は、nに自身の引数mを加算する関数を返します。 この関数はCommon Lispでは動作しますが、Emacs Lispではだめです。 というのは、make-addの呼び出しを抜けると、 変数nは実引数2に束縛されなくなるからです。

(defun make-add (n)
    (function (lambda (m) (+ n m))))  ; 関数を返す
     => make-add
(fset 'add2 (make-add 2))  ; 関数add2を
                           ;   (make-add 2)を使って定義する
     => (lambda (m) (+ n m))
(add2 4)                   ; 4に2を加算してみる
error--> Symbol's value as variable is void: n

Lispの方言のいくつかには『クロージャ』(closure)があります。 それは関数のようなオブジェクトですが、追加の変数束縛を記録します。 Emacs Lispにはクロージャはありません。


Node:Impl of Scope, Next:, Previous:Extent, Up:Variable Scoping

動的スコープの実装

(Emacs Lispの実際の動作とは異なるが)単純な実装例が、 動的束縛を理解する助けになるでしょう。 この技法を深い束縛(ディープバインディング、deep binding)と呼び、 初期のLispシステムで使われていました。

変数・値の対である束縛のスタックがあるとしましょう。 関数やフォームletに入ると、 引数やローカル変数の束縛をスタックに積みます。 束縛を作った構造から抜けるとそれらの束縛を取りさります。

変数の値は、スタックの先頭から底へ向けてその変数の束縛を探索します。 その束縛から得る値が変数の値になります。 変数に設定するには、現在の束縛を探して、その束縛に新たな値を格納します。

これからわかるように、関数の束縛は、その関数の実行中には、 たとえ別の関数を呼び出していても、存続しています。 これが束縛の存続が動的であるという理由です。 また、その束縛が有効である期間中ならば、同じ変数を使えば他の関数からも 束縛を参照できるのです。 これがスコープが無限であるという理由です。

GNU Emacs Lispにおいて、変数のスコープの実際の実装には、 浅い束縛(シャローバインディング、shallow binding)と呼ばれる 技法を用いています。 各変数には現在値を保存しておく標準の場所、シンボルの値セルがあります。

浅い束縛では、変数の設定は値セルに値を格納することで動作します。 新たな束縛を作成すると(以前の束縛に属する)古い値をスタックに積み、 新たなローカル値を値セルに格納します。 束縛を解くときには、古い値をスタックから取り出して値セルに格納します。

浅い束縛を用いる理由は、束縛を探索する必要がないため、 深い束縛と同じ結果を持ちながら高速に動作するからです。


Node:Using Scoping, Previous:Impl of Scope, Up:Variable Scoping

動的スコープの正しい使い方

ある関数で変数を束縛し別の関数でそれを使うことは、強力な技法ですが、 なんの制限もせずに使うとプログラムを理解し難いものにしてしまいます。 この技法を見通しよく使うための2つの方法があります。

いずれの場合でも、変数はdefvarで定義するべきです。 これは、関数間での変数の使い方を見るように伝えることで、 他人が読者のプログラムを理解するのを助けます。 また、バイトコンパイラからの警告も防ぎます。 変数名が衝突しないようにも注意しましょう。 xのような短い名前を使わないでください。


Node:Buffer-Local Variables, Next:, Previous:Variable Scoping, Up:Variables

バッファローカルな変数

グローバルとローカルの変数束縛は、 ほとんどのプログラム言語にいろいろな形であります。 Emacsには、あまり普通でない追加の種類の変数束縛があります。 1つのバッファだけに適用されるバッファローカルな束縛、 1つのフレームだけに適用されるフレームローカルな束縛です。 異なるバッファやフレームごとに変数に異なる値があるということは、 重要なカスタマイズ技法です。

本節では、バッファローカルな束縛を説明します。 フレームローカルな束縛については、つぎの節と See Frame-Local Variables。 (各端末にローカルな束縛を持つ変数も少数ある。 see Multiple Displays。)


Node:Intro to Buffer-Local, Next:, Up:Buffer-Local Variables

バッファローカルな変数の紹介

バッファローカルな変数には、特定のバッファに関連したバッファローカルな 束縛があります。 この束縛は、そのバッファがカレントバッファであるときに有効になります。 さもなければなんの効果もありません。 バッファローカルな束縛が有効なときに変数に設定すると、 新しい値はその束縛に入り、他の束縛は変更されません。 つまり、その変更は、変更を行ったバッファだけで見ることができるのです。

変数の通常の束縛、つまり、特定のバッファに関連していない束縛を デフォルトの束縛(default binding)と呼びます。 多くの場合、これはグローバル束縛です。

変数は、あるバッファ群ではバッファローカルな束縛を持ち、 他のバッファではそのような束縛を持たないようにできます。 変数に対する独自の束縛を持たないバッファすべてでは、 デフォルトの束縛を共有します。 (これには、新たに作成されるバッファも含む。) バッファローカルな束縛を持たないバッファで変数に設定すると、 (状況を複雑にするフレームローカルな束縛はないと仮定して) デフォルトの束縛を使います。 したがって、新たな値はデフォルトの束縛を見るバッファすべてで見えます。

バッファローカルな束縛のもっとも一般的な使い方は、 メジャーモードでコマンドのふるまいを制御する変数に変更することです。 たとえば、CモードやLispモードでは、変数paragraph-startを設定して、 空行だけが段落を区切るように指定します。 これには、CモードやLispモードになったバッファでは、 変数をバッファローカルにしてから、 そのモード用の新たな値を変数に設定するのです。 See Major Modes

バッファローカルな束縛を作る普通の方法は、 make-local-variableです。 メジャーモードのコマンドは典型的にこれを使います。 これはカレントバッファだけに影響します。 (これから作成するものも含めて)他のすべてのバッファは、 それ専用のバッファローカルな束縛を明示的に与えない限り、 デフォルト値を共有し続けます。

より強力な操作は、make-variable-buffer-localを呼び出して 変数を自動的にバッファローカルにするように印を付けることです。 これは、これから作成するものも含めたバッファすべてで、 変数をバッファローカルにすると考えることができます。 より正確には、変数がカレントバッファにローカルでなければ、 自動的に変数をカレントバッファにローカルにするように設定する効果があります。 すべてのバッファは通常どおり変数のデフォルト値を共有して始まりますが、 変数に設定するとカレントバッファにバッファローカルな束縛を作ります。 新たな値はバッファローカルな束縛に格納され、デフォルトの束縛は変更しません。 つまり、どのバッファでもデフォルト値をsetqでは変更できません。 デフォルト値を変更する唯一の方法は、setq-defaultを使うことです。

警告: 複数のバッファにおいて変数にバッファローカルな値があるときに、 変数をletで束縛してから、 別の束縛が有効である別のバッファに切り替えてletを抜けると、 Emacsをとても混乱させることになる。 こうすると、バッファローカルな束縛とデフォルトの束縛を混ぜ合わせてしまう。

混乱を避けるために、このような変数の使い方は避けてください。 別のバッファに切り替える各コード部分をsave-excursionで囲めば、 このような問題はありません。

(setq foo 'b)
(set-buffer "a")
(make-local-variable 'foo)
(setq foo 'a)
(let ((foo 'temp))
  (set-buffer "b")
  body...)
foo => 'a      ; バッファaの古いバッファローカルな値が
               ;   現在のデフォルト値
(set-buffer "a")
foo => 'temp   ; 消えているべきローカルなletの値が
               ;   バッファaの現在のバッファローカルな値

しかし、つぎに示すようにsave-excursionを使えば、この問題を回避できます。

(let ((foo 'temp))
  (save-excursion
    (set-buffer "b")
    body...))

body内でのfooへの参照は、 バッファbのバッファローカルな束縛を使います。

ファイルでローカル変数の値を指定していると、 そのファイルを訪問したときに、それらはバッファローカルな値になります。 See File Variables


Node:Creating Buffer-Local, Next:, Previous:Intro to Buffer-Local, Up:Buffer-Local Variables

バッファローカルな束縛の作成と削除

make-local-variable variable コマンド
この関数は、カレントバッファにおいて、 variable(シンボル)のバッファローカルな束縛を作る。 他のバッファは影響されない。 返す値はvariable

variableのバッファローカルな値は、 variableの以前と同じ値で始まる。 variableが空であれば、空のままである。

;; バッファb1では、
(setq foo 5)                ; すべてのバッファに影響する
     => 5
(make-local-variable 'foo)  ; b1にローカル
     => foo
foo                         ; これは値を
     => 5                   ;   変えない
(setq foo 6)                ; b1での値を
     => 6                   ;   変更する
foo
     => 6

;; バッファb2では、値は変わっていない
(save-excursion
  (set-buffer "b2")
  foo)
     => 5

変数のlet束縛の内側でその変数をバッファローカルにしても、 そのバッファがletに入るときや抜けるときに カレントバッファになっていないと、正しく動作しない。 これは、letが、異なる種類の束縛を区別しないからであり、 どの変数の束縛を作るかだけを知っているからである。

変数が端末にローカルなときには、この関数はエラーを通知する。 そのような変数は、同時にバッファローカルな束縛を持てない。 See Multiple Displays

注意: フック変数に対してmake-local-variableを使わないこと。 そのかわりにmake-local-hookを使う。 see Hooks

make-variable-buffer-local variable コマンド
この関数は、variable(シンボル)を 自動的にバッファローカルにするように印を付け、 これ以降にその変数に設定しようとすると、 その時点のカレントバッファにローカルにする。

この機能の重要な点は、 (letや他の束縛を作る構文で)変数を束縛しても、 その変数のバッファローカルな束縛を作らないことである。 (setsetqで)変数を設定して初めてそのようにする。

返す値はvariableである。

警告: ユーザーが異なるバッファでは異なったカスタマイズをするかもしれないと いうだけで、ユーザーオプション変数にmake-variable-buffer-localを 使うべきだと仮定しないこと。 ユーザーは、必要ならば、どんな変数でもローカルにできる。 選択はユーザーに任せるのがよい。

2つのバッファが同じ束縛を共有しないことが重要な場面では、 make-variable-buffer-localを使う。 たとえば、異なるバッファでは異なる値を持つことに依存するような Lispプログラムで内部目的に変数を使うときには、 make-variable-buffer-localを使うのが最良である。

local-variable-p variable &optional buffer Function
これは、variableがバッファbuffer (デフォルトはカレントバッファ)において バッファローカルであればtを返し、 さもなければnilを返す。

buffer-local-variables &optional buffer Function
この関数は、バッファbufferのバッファローカルな変数を 記述したリストを返す。 (bufferを省略するとカレントバッファを使う。) バッファローカルな変数とその値を入れた要素から成る連想リスト (see Association Lists)を返す。 しかし、bufferにおける変数のバッファローカルな束縛が空であると、 変数は結果のリストに直接現れる。
(make-local-variable 'foobar)
(makunbound 'foobar)
(make-local-variable 'bind-me)
(setq bind-me 69)
(setq lcl (buffer-local-variables))
    ;; まず、すべてのバッファでローカルな組み込み変数
=> ((mark-active . nil)
    (buffer-undo-list . nil)
    (mode-name . "Fundamental")
    ...
    ;; 続いて、組み込みでないバッファローカルな変数
    ;; これはバッファローカルで、かつ、空
    foobar
    ;; これはバッファローカルで、かつ、空ではない
    (bind-me . 69))

このリストのコンスセルのCDRに新たな値を格納しても、 変数のバッファローカルな値を変更しないことに注意してほしい。

kill-local-variable variable コマンド
この関数は、カレントバッファにおけるvariable(シンボル)の バッファローカルな束縛を(あれば)削除する。 その結果、このバッファでは、variableのデフォルトの束縛が 見えるようになる。 典型的には、variableの値が変わる。 なぜなら、デフォルト値は、削除したバッファローカルな値とは 普通は異なるからである。

自動的にバッファローカルにする印が付いた変数のバッファローカルな束縛を 削除すると、カレントバッファではデフォルト値が見えるようになる。 しかし、変数に再度設定すると、それに対するバッファローカルな束縛が 再度作成される。

kill-local-variablevariableを返す。

この関数がコマンドであるのは、 対話的にバッファローカルな変数を作るのが有用なように、 対話的にバッファローカルな変数を削除するのが有用な場合があるからである。

kill-all-local-variables Function
この関数は、カレントバッファにおいて、 『恒久的』と印付けしてある変数を除いて、 すべてのバッファローカルな変数束縛を削除する。 その結果、バッファでは、ほとんどの変数のデフォルト値が見えるようになる。

この関数は、バッファに属する他のある種の情報もリセットする。 つまり、ローカルキーマップにnil、 構文テーブルに(standard-syntax-table)の値、 大文字小文字テーブルに(standard-case-table)、 略語テーブルにfundamental-mode-abbrev-tableの値を設定する。

この関数が最初に行うことは、 ノーマルフックchange-major-mode-hook(下記参照)を 実行することである。

各メジャーモードコマンドはこの関数を呼び出すことから始める。 つまり、基本(fundamental)モードに切り替え、 それ以前のメジャーモードのほとんどの効果を消しさる。 この処理を保証するために、メジャーモードで設定する変数には、 恒久的の印を付けないこと。

kill-all-local-variablesnilを返す。

change-major-mode-hook Variable
関数kill-all-local-variablesは、最初にこのノーマルフックを実行する。 このフックはメジャーモードに対して、 ユーザーが別のメジャーモードに切り替えていた場合には、 なにか特別なことを行う情報を提供する。 最良の結果を得るためには、この変数をバッファローカルにしておくと その役目を終えると変数は消えてしまい、それ以降のメジャーモードに干渉しない。 see Hooks

バッファローカル変数は、 変数名(シンボル)の属性permanent-localnil以外であると、 恒久的(permanent)です。 恒久的なローカル変数は、編集作業の文脈ではなく、 どのファイルを訪問中であるとかどのように保存するとかに関連する情報に 適しています。


Node:Default Value, Previous:Creating Buffer-Local, Up:Buffer-Local Variables

バッファローカル変数のデフォルト値

バッファローカルな束縛がある変数のグローバル値を、 デフォルト値とも呼びます。 カレントバッファや選択したフレームに変数の独自の束縛がない場合に、 グローバル値を使うからです。

関数default-valueと関数setq-defaultは、 カレントバッファにバッファローカルな束縛があるかどうかに関わらず、 変数のデフォルト値を参照したり変更したりします。 たとえば、setq-defaultを使って、 ほとんどのバッファのparagraph-startのデフォルト値を変更できます。 この変数のバッファローカルな値があるCモードやLispモードのバッファで 行ってもこれは動作します。

スペシャルフォームdefvardefconstも、 バッファローカルやフレームローカルな値ではなく、 (変数に設定する場合には)デフォルト値を設定します。

default-value symbol Function
この関数は、symbolのデフォルト値を返す。 この値は、この変数に対して独自の値を持たないバッファやフレームで見える 値である。 symbolがバッファローカルでなければ、 これは、symbol-value(see Accessing Variables)と等価。

default-boundp symbol Function
関数default-boundpは、 symbolのデフォルト値が空でないことを調べる。 (default-boundp 'foo)nilを返せば、 (default-value 'foo)はエラーになる。

default-boundpは、boundpsymbol-valueに対応するように、 default-valueに対応する。

setq-default [symbol form]... Special Form
このスペシャルフォームは、各symbolに、 対応するformの評価結果である新たなデフォルト値を与える。 symbolは評価しないが、formは評価する。 フォームsetq-defaultの値は、最後のformの値である。

symbolがカレントバッファでバッファローカルではなく、かつ、 自動的にバッファローカルにする印が付いていなければ、 setq-defaultsetqと同じ効果がある。 symbolがカレントバッファでバッファローカルならば、 (バッファローカルな値を持たない)別のバッファが見る値を変更し、 カレントバッファが見る値は変更しない。

;; バッファfooにおいて、
(make-local-variable 'buffer-local)
     => buffer-local
(setq buffer-local 'value-in-foo)
     => value-in-foo
(setq-default buffer-local 'new-default)
     => new-default
buffer-local
     => value-in-foo
(default-value 'buffer-local)
     => new-default

;; (新たな)バッファbarでは、
buffer-local
     => new-default
(default-value 'buffer-local)
     => new-default
(setq buffer-local 'another-default)
     => another-default
(default-value 'buffer-local)
     => another-default

;; バッファfooに戻ってみると
buffer-local
     => value-in-foo
(default-value 'buffer-local)
     => another-default

set-default symbol value Function
この関数はsetq-defaultに似ているが、 symbolは普通どおりに評価される引数である。
(set-default (car '(a b c)) 23)
     => 23
(default-value 'a)
     => 23


Node:Frame-Local Variables, Next:, Previous:Buffer-Local Variables, Up:Variables

フレームローカルな変数

変数にバッファローカルな束縛があるように、 変数にはフレームローカルな束縛もあります。 これらの束縛は1つのフレームに属し、 そのフレームを選択しているときに有効になります。 フレームローカルな束縛は、実際にはフレームパラメータです。 特定のフレームでフレームローカルな束縛を作るには modify-frame-parametersを呼び出し、 パラメータ名として変数名を指定します。

特定の変数に対するフレームローカルな束縛を有効にするには、 関数make-variable-frame-localを呼び出します。

make-variable-frame-local variable コマンド
variableに対してフレームローカルな束縛を使うようにする。 この関数そのものはvariableに対してフレームローカルな束縛を作成しない。 しかし、フレームパラメータとしてvariableの値を持つフレームが すでに存在すれば、その値は自動的にフレームローカルな束縛になる。

変数が端末にローカルであると、この関数はエラーを通知する。 そのような変数はフレームローカルな束縛を同時には持てないからである。 see Multiple Displays。 Emacsで特別に実装されている少数の変数は(普通) バッファローカルになることができるが、フレームローカルにはならない。

バッファローカルな束縛はフレームローカルな束縛に優先します。 変数fooを考えてみましょう。 カレントバッファにfooのバッファローカルな束縛があると、 その束縛が有効になります。 選択したフレームにfooのフレームローカルな束縛があると、 その束縛が有効になります。 さもなければ、fooのデフォルトの束縛が有効になります。

つぎに例を示します。 まず、fooの束縛を準備しておきます。

(setq f1 (selected-frame))
(make-variable-frame-local 'foo)

;; b1において、fooのバッファローカルな束縛を作る
(set-buffer (get-buffer-create "b1"))
(make-local-variable 'foo)
(setq foo '(b 1))

;; 新しいフレームでfooのフレームローカルな束縛を作る
;; そのフレームをf2に格納する
(setq f2 (make-frame))
(modify-frame-parameters f2 '((foo . (f 2))))

では、さまざまな文脈でfooを調べてみましょう。 バッファb1がカレントバッファであれば、 選択したフレームに関係なく、 b1のバッファローカルな束縛が有効になっています。

(select-frame f1)
(set-buffer (get-buffer-create "b1"))
foo
     => (b 1)

(select-frame f2)
(set-buffer (get-buffer-create "b1"))
foo
     => (b 1)

さもなければ、フレームの束縛を使う可能性があります。 フレームf2を選択していると、 そのフレームローカルな束縛が有効になります。

(select-frame f2)
(set-buffer (get-buffer "*scratch*"))
foo
     => (f 2)

カレントバッファにもフレームにも束縛がなければ、 デフォルトの束縛を使います。

(select-frame f1)
(set-buffer (get-buffer "*scratch*"))
foo
     => nil

変数の有効な束縛がフレームローカルな束縛であるとき、 変数に設定するとその束縛を変更します。 frame-parametersでその結果を見ることができます。

(select-frame f2)
(set-buffer (get-buffer "*scratch*"))
(setq foo 'nobody)
(assq 'foo (frame-parameters f2))
     => (foo . nobody)


Node:Future Local Variables, Previous:Frame-Local Variables, Up:Variables

将来のローカル変数

フレームに分類されるものでローカルな束縛というアイデアを考察しています。 たとえば、すべてのカラーフレーム、暗い背景色のすべてのフレームなどです。 この機能が本当に有用なのか明らかでないので、それらをまだ実装してはいません。 after-make-frame-hookに関数を追加して、 各フレームの適切な状態に応じたフレームパラメータを設定すれば、 同じような結果を得られます。

ウィンドウローカルな束縛を実装することも可能です。 これが有用である多くの状況を知りませんが、 バッファローカルな束縛を持つ間接バッファ(see Indirect Buffers)で、 そのような状況をより堅牢に扱えると思います。

これら2種類のローカル束縛のいずれかを必要とする十分な数のアプリケーションが みつかれば、Emacsの将来の版でそのような束縛を提供するでしょう。


Node:Functions, Next:, Previous:Variables, Up:Top

関数

Lispプログラムは、主にLisp関数から構成されます。 本章では、関数とはなにか、引数をどのように受け取るのか、 どのように関数を定義するのかを説明します。


Node:What Is a Function, Next:, Up:Functions

関数とはなにか

一般的には、関数とは、引数(arguments)と呼ばれる値を与えられ、 計算を行うための規則です。 この計算結果を関数の値と呼びます。 計算では副作用、つまり、変数の値やデータ構造の内容に継続する変更 を伴うこともできます。

Emacs Lispの関数や関数のようなオブジェクトに関する重要な用語をあげておきます。

関数
Emacs Lispでは、Lispプログラムにおいて引数に適用可能ものは なんであれ関数(function)である。 Lispで書いた関数を意味する場合もある。 スペシャルフォームやマクロは関数ではない。
基本関数
基本関数(primitive)は、carappendなどのCで書いた Lispから呼び出し可能な関数である。 これらの関数は、組み込み関数とかsubrsとも呼ぶ。 (スペシャルフォームは基本関数とも考えられる。)

関数を基本関数として実装する理由は、 それが基本的なものである、 それがオペレーティングシステムの機能に対する 低レベルのインターフェイスを提供する、 あるいは、高速に動作する必要があるからである。 基本関数を変更したり追加する唯一の方法は、 Cソースを変更してエディタを再コンパイルすることである。 see Writing Emacs Primitives

ラムダ式
ラムダ式(lambda expression)は、Lispで書いた関数である。 これらについては以下の節で説明する。
スペシャルフォーム
スペシャルフォーム(special form)は関数に似た基本関数であるが、 その引数すべてを普通のようには評価しない。 引数の一部を評価したり、普通とは異なる順序で評価したり、 複数回評価したりする。 多くのスペシャルフォームについては、 Control Structuresで説明してある。
マクロ
マクロ(macro)は、プログラマがLispで定義した構文である。 マクロと関数との違いは、マクロは、 読者が書いたLisp式をもとの式のかわりに評価される等価な式に変換する。 マクロは、スペシャルフォームでできる種類のことを Lispプログラマに提供する。 マクロの定義方法と使い方については、see Macros
コマンド
コマンド(command)とは、 command-executeが起動できるオブジェクトであり、 キー列に対して定義できる。 いくつかの関数はコマンドである。 Lispで書いた関数に対話宣言(see Defining Commands)が含まれているとき、 その関数はコマンドである。 そのような関数は、他の関数と同様にLisp式から呼び出すことができる。 その場合、関数がコマンドであるという事実は関係ない。

キーボードマクロ(文字列かベクトル)もコマンドであるが、 それらは関数ではない。 シンボルの関数定義がコマンドであれば、シンボルはコマンドである。 そのようなシンボルは、M-xで起動できる。 シンボルの定義が関数であれば、シンボルは関数でもある。

打鍵コマンド
打鍵コマンド(keystroke command)とは、 キー列(典型的には1から3打鍵)にバインドされたコマンドである。 ここでの区別は、Emacs以外のエディタの『コマンド』の意味との 混乱を防ぐためであるが、 Lispプログラムにとっては、この区別は普通は重要ではない。
バイトコード関数
バイトコード関数(byte-code function)とは、 バイトコンパイラでコンパイルした関数である。 see Byte-Code Type

functionp object Function
この関数は、objectが、なんらかの関数、スペシャルフォーム、 マクロであれば、tを返す。

subrp object Function
この関数は、objectが組み込み関数(つまり、Lisp基本関数)であれば tを返す。
(subrp 'message)            ; messageはシンボルであり、
     => nil                 ;   subrオブジェクトではない
(subrp (symbol-function 'message))
     => t

byte-code-function-p object Function
この関数は、objectがバイトコード関数であればtを返す。 たとえば、つぎのとおり。
(byte-code-function-p (symbol-function 'next-line))
     => t


Node:Lambda Expressions, Next:, Previous:What Is a Function, Up:Functions

ラムダ式

Lispで書いた関数はつぎのようなリストです。

(lambda (arg-variables...)
  [documentation-string]
  [interactive-declaration]
  body-forms...)

このようなリストをラムダ式(lambda expression)と呼びます。 Emacs Lispでは、これは式として正しいもので、 それ自身に評価されます。 Lispの他の方言では、ラムダ式は正しい式ではありません。 いずれの場合でも、その主な用途は式として評価することではなく、 関数として呼び出すことです。


Node:Lambda Components, Next:, Up:Lambda Expressions

ラムダ式の構成要素

ラムダ式の先頭要素は、つねにシンボルlambdaです。 このシンボルは、リストが関数を表すことを示します。 関数はlambdaで始まると定義してあるのは、 他の目的向けの他のリストが誤って正しい関数とならないようにするためです。

第2要素は、シンボルのリスト、つまり、引数変数名です。 これをラムダリスト(lambda list)と呼びます。 Lisp関数が呼ばれると、引数値をラムダリストの変数に対応させ、 指定した値を持つローカル束縛になります。 See Local Variables

説明文字列は、関数定義の内側にあるLisp文字列オブジェクトであり、 Emacsのヘルプ機能に対して関数を記述します。 See Function Documentation

対話宣言は、(interactive code-string)の形式のリストです。 この宣言は、関数が対話的に使われたときに、 どのように引数を与えるかを指定します。 この宣言を有する関数をコマンド(commands)と呼びます。 コマンドは、M-xで呼び出したり、キーにバインドできます。 このように呼ばれることを意図していない関数には、 対話宣言を付けてはいけません。 対話宣言の書き方については、See Defining Commands

残りの要素は、関数の本体(body)です。 関数の動作を行うLispコードです (Lispプログラマとしては、『評価するべきLispフォームのリスト』という)。 関数が返す値は、本体の最後の要素が返す値です。


Node:Simple Lambda, Next:, Previous:Lambda Components, Up:Lambda Expressions

簡単なラムダ式の例

つぎの関数を考えてみましょう。

(lambda (a b c) (+ a b c))

この関数を呼び出すには、つぎのように式のCARにこの関数を書きます。

((lambda (a b c) (+ a b c))
 1 2 3)

この呼び出しは、変数aには1、変数bには2、 変数cには3を束縛し、ラムダ式の本体を評価します。 本体の評価ではこれらを加算し、結果6を生じます。 したがって、この関数呼び出しは6を返します。

つぎの例のように、他の関数呼び出しの結果が引数になることもあります。

((lambda (a b c) (+ a b c))
 1 (* 2 3) (- 5 4))

これは、引数、1(* 2 3)(- 5 4)を 左から右へ順に評価します。 そして、引数値、1、6、1にラムダ式を適用し、値8を生じます。

このようにフォームのCARとしてラムダ式を書くのは、 あまり便利ではありません。 スペシャルフォームlet(see Local Variables)を使って、 ローカル変数を作ってそれらに値を与えても、同じ結果を得られます。 さらに、letは見通しがよく使いやすいです。 実用上、ラムダ式は、シンボルの関数定義として格納して名前付き関数を作るか、 他の関数に引数として渡します(see Anonymous Functions)。

しかしながら、スペシャルフォームletがなかった初期のLispでは、 ラムダ式を明示的に呼び出すことはとても便利でした。 その頃では、ラムダ式はローカル変数を束縛し初期化する唯一の方法でした。


Node:Argument List, Next:, Previous:Simple Lambda, Up:Lambda Expressions

引数リストのその他の機能

単純な関数の例(lambda (a b c) (+ a b c))では、 3つの引数変数を指定しているので、これは3引数で呼び出す必要があります。 2引数や4引数で呼び出そうとすると、 エラーwrong-number-of-argumentsになります。

特定の引数を省略できる関数を書けると便利なことがしばしばあります。 たとえば、関数substringは3つの引数、つまり、 文字列、開始と終了の添字を取りますが、 第3引数を省略するとデフォルトは文字列のlengthになります。 list+のように、 特定の関数では任意個数の引数を受け付けると便利なこともあります。

関数呼び出し時に省略してもよい引数を指定するには、 省略可能な引数のまえにキーワード&optionalを含めるだけです。 0個以上の引数のリストを指定するには、 最後の引数のまえにキーワード&restを含めます。

したがって、引数リストの完全な構文はつぎのようになります。

(required-vars...
               ; 必須の引数
 [&optional optional-vars...]
               ; 省略可能な引数
 [&rest rest-var])
               ; 残りの引数

角括弧は、&optional&restの節や それに続く変数は省略できることを示します。

関数呼び出し時には、各required-varsに1つの実引数が必要です。 0個以上のoptional-varsにも実引数が必要ですが、 ラムダリストに&restがない限り、 optional-varsの個数を超える実引数は指定できません。 &restがあれば、任意個の余分な実引数を指定できます。

&optional&restに対応する実引数を省略すると、 それらのデフォルトはnilです。 関数では、nilを明示した引数と省略した引数とを区別する方法はありません。 しかしながら、関数本体でnilを適切な意味ある値の省略と みなすことは自由です。 substringはそのようにしています。 substringの第3引数がnilであると、 指定した文字列の長さを使うことを意味します。

Common Lispに関した注意: Common Lispでは、省略可能引数を省略したときのデフォルト値を関数で指定できる。 Emacs Lispではつねにnilを使う。 Emacs Lispには、明示的に引数を指定したかどうか調べる 『supplied-p』変数はない。

たとえば、引数リストはつぎのようになります。

(a b &optional c d &rest e)

これは、abに最初の2つの実引数を束縛し、これらは必須です。 さらに1個か2個の引数を指定すると、 それらは、それぞれcdに束縛します。 最初の4個よりあとの引数はリストにまとめ、 eにそのリストを束縛します。 引数が2個だけであると、cnilです。 引数が2個か3個だけであると、dnilです。 引数が4個以下であると、enilです。

省略可能な引数のあとに必須引数を指定する方法はありませんし、 それには意味がありません。 なぜそうなのかを理解するために、上の例で、 cは省略可能であり、dは必須であるとしましょう。 3つの実引数を指定したとき、どの引数を3番目と考えるのでしょう? 同様に、&restのうしろに余分に(必須、もしくは省略可能な)引数が あっても意味がありません。

引数リストと正しい呼び出しの例をあげます。

((lambda (n) (1+ n))                ; 1個が必須
 1)                                 ; 引数は1個だけ
     => 2
((lambda (n &optional n1)           ; 1個は必須、1個は省略可
         (if n1 (+ n n1) (1+ n)))   ; 引数は1個か2個
 1 2)
     => 3
((lambda (n &rest ns)               ; 1個は必須、あとは残り全部
         (+ n (apply '+ ns)))       ; 引数は1個以上いくつでもよい
 1 2 3 4 5)
     => 15


Node:Function Documentation, Previous:Argument List, Up:Lambda Expressions

関数の説明文字列

ラムダ式には、ラムダリストの直後に 説明文字列(documentation string)があってもかまいません。 この文字列は関数の実行には影響しません。 コメントのようなものですが、Lisp内部に現れる系統的なコメントであり、 Emacsのヘルプ機能が使用します。 documentation-stringの参照方法については、See Documentation

読者のプログラムの関数すべてに、 たとえ内部的に使用されるものであっても説明文字列を与えることはよいことです。 説明文字列はコメントに似ていますが、参照するのはもっと簡単です。

説明文字列の先頭行は、その1行で完結しているべきです。 というのは、aproposは先頭行だけを表示するからです。 関数の機能をまとめた1つか2つの文にしましょう。

説明文字列の先頭は、ソースファイル上では普通字下げしてあるでしょうが、 それらの空白は文字列を始めるダブルクォートのまえにありますから、 それらは文字列の一部ではありません。 説明文字列の残りの行を字下げして、 プログラムソース上でテキスト行が揃うようにする人もいます。 しかし、それはまちがいです。 後続の行の字下げは文字列の内側にあります。 ソースファイルで綺麗に見えても、 ヘルプコマンドの表示では不恰好になります。

関数の必須の構成要素(本体)があとに続くのに、 説明文字列を省略できるのを不思議に思うかもしれません。 文字列を評価すると、副作用なしに、その文字列を返すので、 それが本体の最後のフォームでなければ、なんの効果もありません。 したがって、実用上、本体の最初のフォームと 説明文字列を混同することはありません。 本体のフォームが文字列だけであると、 それは戻り値でもあり説明文字列でもあります。


Node:Function Names, Next:, Previous:Lambda Expressions, Up:Functions

関数を命名する

ほとんどの計算機言語では、各関数には名前があります。 名前のない関数という考えは本質的ではありません。 Lispでは、もっとも厳密にいえば、関数には名前はありません。 関数は、先頭要素が単にlambdaであるリスト、 バイトコード関数オブジェクト、あるいは、基本関数のsubrオブジェクトです。

しかしながら、シンボルは関数の名前として働きます。 シンボルの関数セル(function cell、see Symbol Components)に 関数を入れると、このようになります。 そうすると、シンボルそのものは正当な呼び出し可能な関数となり、 関数セルが参照するリストやsubrオブジェクトと等価になります。 関数セルの内容をシンボルの関数定義(function definition)とも呼びます。 シンボルのかわりにシンボルの関数定義を使う処理を シンボルの関数間接(symbol function indirection)と呼びます。 See Function Indirection

実用上、ほとんどすべての関数には、このようにして名前が付いていて、 その名前で参照します。 たとえば、シンボルcarは、 その関数セルに基本関数のsubrオブジェクト#<subr car>が格納してあるので、 その動作を行う関数として動作します。

関数に名前を与えるのは、Lisp式からその名前で参照できると便利だからです。 #<subr car>のような基本関数のsubrオブジェクトでは、 名前はそれらを参照する唯一の方法です。 そのようなオブジェクトには入力構文はありません。 Lispで書いた関数では、明示的なラムダ式より名前を使うほうがより便利です。 また、関数に名前があればそれを参照できます。 つまり、再帰呼び出しができます。 関数の名前をその定義そのものに書くことは、 関数定義がそれ自身を指すようにする (これは不可能ではないにしても、実用上はさまざまな欠点がある)よりは、 とても便利です。

関数を指名するシンボルで関数をしばしば識別します。 たとえば、しばしば『関数car』といって、 シンボルcarと関数定義である基本関数のsubrオブジェクトとを区別しません。 ほとんどの目的には、区別する必要はありません。

たとえそうであっても、関数に一意な名前は必要ないことを 心に留めておいてください。 関数オブジェクトは普通1つのシンボルの関数セルだけに現れますが、 これは単なる便法です。 fsetを使って、複数のシンボルに格納するのは簡単です。 そうすると、各シンボルは同じ関数を同等に指名します。

関数名として使うシンボルは、変数としても使えます。 シンボルのこれら2つの使い方は独立していて衝突しません。 (SchemeなどのLispの方言のなかには、 シンボルの値とその関数定義を区別しないものもある。 変数としてのシンボルの値は、その関数定義でもある。) シンボルに関数定義を与えていないと、そのシンボルを関数としては使えません。 これは、シンボルに変数としての値があるかどうかには関係しません。


Node:Defining Functions, Next:, Previous:Function Names, Up:Functions

関数を定義する

関数を作成するときには、普通、関数に名前を与えます。 これを関数を定義すると呼び、 スペシャルフォームdefunで行います。

defun name argument-list body-forms Special Form
defunは、新たにLisp関数を定義する普通の方法である。 これは、シンボルnameをつぎのような関数として定義する。
(lambda argument-list . body-forms)

defunは、このラムダ式をnameの関数セルに格納する。 値nameを返すが、普通、これは無視する。

前述(see Lambda Expressions)のように、 argument-listは引数名のリストであり、 キーワード&optional&restが入っていてもよい。 また、body-formsの最初の2つは、説明文字列と対話宣言でもよい。

同一のシンボルnameを変数として使っていても衝突はない。 というのは、シンボルの値セルは関数セルとは独立だからである。 see Symbol Components

例を示そう。

(defun foo () 5)
     => foo
(foo)
     => 5

(defun bar (a &optional b &rest c)
    (list a b c))
     => bar
(bar 1 2 3 4 5)
     => (1 2 (3 4 5))
(bar 1)
     => (1 nil nil)
(bar)
error--> Wrong number of arguments.

(defun capitalize-backwards ()
  "Upcase the last letter of a word."
  (interactive)
  (backward-word 1)
  (forward-word 1)
  (backward-char 1)
  (capitalize-word 1))
     => capitalize-backwards

既存の関数を意図せずに再定義しないように注意すること。 defunは、たとえcarなどの基本関数であっても、 なんの躊躇も注意もせずに再定義してしまう。 既存関数の再定義は注意深く行うが、 不本意な再定義と熟考した再定義を区別する方法はない。

defalias name definition Function
このスペシャルフォームは、 シンボルnameを定義definition(任意の正しいLisp関数)とする 関数として定義する。

defaliasを使う正しい場所は、 特定の関数名が定義されている場所である。 特に、ロード中のソースファイルで明示的に名前が現れている場所である。 というのは、defaliasは、defunと同様に、 関数が定義されたファイルを記録するからである(see Unloading)。

一方、他の目的で関数定義を操作するプログラムでは、 そのような記録を保持しないfsetを使うのがよい。

defunのように関数を定義し、かつ、 Lispコンパイラに関数定義を展開するように指示する defsubstも参照してください。 See Inline Functions


Node:Calling Functions, Next:, Previous:Defining Functions, Up:Functions

関数呼び出し

関数を定義することは、全体の半分でしかありません。 関数を呼ぶまでは、つまり、実行を命じなければ、関数はなにもしません。 関数呼び出しは起動(invocation)ともいいます。

関数を起動するもっとも一般的な方法は、リストを評価することです。 たとえば、リスト(concat "a" "b")を評価すると、 関数concatを引数"a""b"で呼び出します。 評価についてはSee Evaluation

読者のプログラムで式としてリストを書くときには、 呼び出す関数名を読者のプログラムに書きます。 つまり、プログラムを書くときに、 どの関数をどれだけの引数で呼び出すかを指定できることを意味します。 これが、普通にしたいことでしょう。 呼び出す関数を実行時に計算する必要がある場合もあるでしょう。 それには、関数funcallを使います。 渡す引数の個数を実行時に決定する必要があるときには、 applyを使います。

funcall function &rest arguments Function
funcallは、functionargumentsで呼び出し、 functionがなにを返そうともそれを返す。

funcallは関数なので、functionの呼び出しを評価するまえに functionを含めた引数すべてを評価する。 つまり、呼び出す関数を得るためのどんな式でも使えることを意味する。 また、funcallは、読者がargumentsに書いた式を見ることはなく、 それらの値だけを見ることになる。 これらの値は、functionを呼び出す操作において、 2回目の評価を行うことはないfuncallは、通常の関数呼び出し処理において、 引数を評価し終えたところから始める。

引数functionは、Lisp関数か基本関数である必要がある。 スペシャルフォームやマクロは許されない。 それらには、『未評価』の引数式を与えたときだけ意味があるからである。 funcallではそのようにできない。 なぜなら、上の説明でわかるように、 未評価の引数をまったく知らないからである。

(setq f 'list)
     => list
(funcall f 'x 'y 'z)
     => (x y z)
(funcall f 'x 'y '(z))
     => (x y (z))
(funcall 'and t nil)
error--> Invalid function: #<subr and>

これらの例をapplyの例と比較してほしい。

apply function &rest arguments Function
applyは、funcallのように、 functionargumentsで呼び出すが、1点だけ異なる。 argumentsの最後はオブジェクトのリストであり、 functionにはこれを、単一のリストではなく、個々の引数として渡す。 これを、applyは、 このリストの個々の要素が引数となるように分配するという。

applyは、functionの呼び出し結果を返す。 funcallと同様に、functionはLisp関数か基本関数である必要がある。 スペシャルフォームやマクロは、applyでは意味がない。

(setq f 'list)
     => list
(apply f 'x 'y 'z)
error--> Wrong type argument: listp, z
(apply '+ 1 2 '(3 4))
     => 10
(apply '+ '(1 2 3 4))
     => 10

(apply 'append '((a b c) nil (x y z) nil))
     => (a b c x y z)

applyを使った興味深い例として、 Mapping Functionsmapcarの説明を見てほしい。

Lisp関数にとっては、引数として関数を受け取ったり、 データ構造(特に、フック変数や属性リスト)内の関数を探して funcallapplyを使ってそれを呼び出すことは一般的です。 関数引数を受け付ける関数を しばしばファンクショナル(functionals)と呼びます。

場合によっては、ファンクショナルを呼び出すときには、 引数としてなにもしない関数(no-op)を指定できると有用です。 つぎのものは、2種類のなにもしない関数です。

identity arg Function
この関数はargを返し、副作用を持たない。

ignore &rest args Function
この関数は引数を無視し、nilを返す。


Node:Mapping Functions, Next:, Previous:Calling Functions, Up:Functions

マップ関数

マップ関数(mapping function)は、 リストや他の集まりの各要素に指定した関数を適用します。 Emacs Lispにはそのような関数がいくつかあります。 mapcarmapconcatはリストを走査するもので、ここで説明します。 オブジェクト配列obarray内のシンボルについて マップする関数mapatomsについては、 See Creating Symbols

これらのマップ関数では、文字テーブルは扱えません。 というのは、文字テーブルは疎な配列であり、その添字範囲も非常に大きいからです。 文字テーブルの疎な性質を考慮して文字テーブルについてマップするには、 関数map-char-table(see Char-Tables)を使います。

mapcar function sequence Function
mapcarは、sequenceの各要素に順にfunctionを適用し、 結果のリストを返す。

引数sequenceは文字テーブル以外の任意の種類のシーケンスでよい。 つまり、リスト、ベクトル、ブールベクトル、あるいは、文字列である。 結果はつねにリストである。 結果の長さはsequenceの長さと同じである。


たとえば、つぎのとおり。
(mapcar 'car '((a b) (c d) (e f))) => (a c e) (mapcar '1+ [1 2 3]) => (2 3 4) (mapcar 'char-to-string "abc") => ("a" "b" "c") ;; my-hooksの各関数を呼び出す (mapcar 'funcall my-hooks) (defun mapcar* (function &rest args) "Apply FUNCTION to successive cars of all ARGS. Return the list of results." ;; リストをつくしていなければ (if (not (memq 'nil args)) ;; CARに関数を適用する (cons (apply function (mapcar 'car args)) (apply 'mapcar* function ;; Recurse for rest of elements. (mapcar 'cdr args))))) (mapcar* 'cons '(a b c) '(1 2 3 4)) => ((a . 1) (b . 2) (c . 3))

mapconcat function sequence separator Function
mapconcatは、sequenceの各要素にfunctionを適用する。 それらの結果は、文字列である必要があり、連結される。 mapconcatは、結果の文字列のあいだに文字列separatorを挿入する。 普通、separatorは、空白やコンマ、その他の句読点を含む。

引数functionは、引数を1つ取る関数であり、 文字列を返す必要がある。 引数sequenceは、文字テーブル以外の任意の種類のシーケンスでよい。 つまり、リスト、ベクトル、ブールベクトル、あるいは、文字列である。

(mapconcat 'symbol-name
           '(The cat in the hat)
           " ")
     => "The cat in the hat"

(mapconcat (function (lambda (x) (format "%c" (1+ x))))
           "HAL-8000"
           "")
     => "IBM.9111"


Node:Anonymous Functions, Next:, Previous:Mapping Functions, Up:Functions

無名関数

Lispでは、関数とは、lambdaで始まるリスト、 そのようなリストをコンパイルしたバイトコード関数、 あるいは、基本関数のsubrオブジェクトです。 名前は『余分』なのです。 普通の関数はdefunで定義し、そのとき名前を与えますが、 明示的なラムダ式、つまり、無名関数を使ったほうがより簡素な場合もあります。 そのようなリストは、関数名を使える場面ならば、どこでも使えます。

そのようなリストをどんな方法で作っても、正しい関数となります。 つぎのようにしてもかまわないのです。

(setq silly (append '(lambda (x)) (list (list '+ (* 3 4) 'x))))
=> (lambda (x) (+ 12 x))

これは、(lambda (x) (+ 12 x))のようなリストを計算し、 その値をsillyの値(関数定義ではない!)とします。

この関数はつぎのように呼び出せます。

(funcall silly 1)
=> 13

(silly 1)と書いても動作しない。 なぜなら、この関数は、silly関数定義ではないからである。 sillyには関数定義を与えてなく、 変数としての値を与えただけである。)

ほとんどの場合、無名関数は読者のプログラムに現れる定数です。 たとえば、関数mapcarの引数の1つに渡したいときなどです。 mapcarは、リストの各要素に指定した関数を適用します。

第3引数に関数を取る関数change-propertyを定義します。

(defun change-property (symbol prop function)
  (let ((value (get symbol prop)))
    (put symbol prop (funcall function value))))

ここで、数を2倍する関数を渡してchange-propertyを使う 関数を定義します。

(defun double-property (symbol prop)
  (change-property symbol prop '(lambda (x) (* 2 x))))

このような場合、つぎのように、無名関数をクォートするには、 単純なクォートのかわりにスペシャルフォームfunctionを使います。

(defun double-property (symbol prop)
  (change-property symbol prop
                   (function (lambda (x) (* 2 x)))))

quoteのかわりにfunctionを使った場合に違いがでるのは、 関数double-propertyをコンパイルしたときです。 たとえば、double-propertyの2番目の定義をコンパイルすると、 無名関数もコンパイルされます。 一方、普通のquoteを使った最初の定義をコンパイルすると、 change-propertyへ渡す引数は、書いたとおりのリストです。

(lambda (x) (* x 2))

Lispコンパイラは、このリストが関数に見えたとしても、 このリストを関数とはみなしません。 というのは、コンパイラにはchange-propertyがリストになにを行うか わからないからです。 たぶん、第3要素のCARがシンボル*か どうか調べればよいのでしょう! functionを使うと、コンパイラに対して先へ進んで 定数の関数をコンパイルしても安全であることを伝えます。

関数名をクォートするときにquoteのかわりにfunctionを 書くこともありますが、この用法はコメントのようなものです。

(function symbol) == (quote symbol) == 'symbol

入力構文#'は、functionの省略形です。 たとえば、

#'(lambda (x) (* x x))

は、つぎと等価です。

(function (lambda (x) (* x x)))

function function-object Special Form
このスペシャルフォームは、function-objectを評価せずに function-objectを返す。 この意味ではquoteに等価である。 しかし、これは、Emacs Lispコンパイラに対しては注意書きとして働き、 function-objectを関数としてのみ使う意図があり、 したがって、コンパイルしても安全であることを意味する。 Quotingquoteと比較してほしい。

functionと無名関数を用いた実際的な例は、 Accessing Documentationdocumentationを参照してください。


Node:Function Cells, Next:, Previous:Anonymous Functions, Up:Functions

関数セルの内容の参照

シンボルの関数定義(function definition)とは、 シンボルの関数セルに格納されたオブジェクトです。 ここで説明する関数は、シンボルの関数セルを参照したり、調べたり、 設定したりします。 Function Indirectionの関数indirect-functionも参照してください。

symbol-function symbol Function
これは、symbolの関数セルのオブジェクトを返す。 シンボルの関数セルが空であると、エラーvoid-functionを通知する。

この関数は、返すオブジェクトが正しい関数であるかどうか検査しない。

(defun bar (n) (+ n 2))
     => bar
(symbol-function 'bar)
     => (lambda (n) (+ n 2))
(fset 'baz 'bar)
     => bar
(symbol-function 'baz)
     => bar

シンボルに一度も関数定義を与えていないと、 そのシンボルの関数セルは(void)であるといいます。 いいかえれば、関数セルにはどんなLispオブジェクトも入っていません。 そのようなシンボルを関数として呼び出そうとすると、 エラーvoid-functionを通知します。

空(void)は、nilやシンボルvoidと違うことに注意してください。 シンボルnilvoidもLispオブジェクトであり、 それらは他のオブジェクトと同様に関数セルに格納できます (そして、それらをdefunで定義しておけば、正しい関数である)。 空の関数セルには、どんなオブジェクトも含まれていません。

シンボルの関数定義が空かどうかはfboundpで調べることができます。 シンボルに関数定義を与えたあとでも、 fmakunboundを使ってふたたび空にできます。

fboundp symbol Function
この関数は、シンボルの関数セルにオブジェクトが入っていればtを返し、 さもなければnilを返す。 オブジェクトが正しい関数であるかどうか検査しない。

fmakunbound symbol Function
この関数はsymbolの関数セルを空にする。 これ以降にこのセルを参照しようとすると、 エラーvoid-functionを引き起こす。 (Void Variablesmakunboundも参照)。
(defun foo (x) x)
     => foo
(foo 1)
     =>1
(fmakunbound 'foo)
     => foo
(foo 1)
error--> Symbol's function definition is void: foo

fset symbol definition Function
この関数は、symbolの関数セルにdefinitionを格納する。 結果はdefinitionである。 通常、definitionは関数か関数名であるべきだが、 そうであるかどうか検査しない。 引数symbolは通常どおり評価される引数である。

この関数の普通の3つの使い方はつぎのとおり。

  • あるシンボルの関数定義を別のものにコピーする。 いいかえれば、関数の別名を作る。 (これを新たな名前の定義と考えるならば、 fsetのかわりにdefaliasを使うべきである。 see Defining Functions。)
  • リストではない関数定義をシンボルに与える。 これは、defunではできない。 たとえば、fsetを使って、s1に関数定義として 別のシンボルs2を与えることができる。 すると、s1は、s2の現在の定義の別名として働く。 (これをs1の定義と考えるのであれば、 やはり、fsetのかわりにdefaliasを使う。)
  • 関数を定義したり変更したりする構文で使う。 defunが基本関数でなかったならば、 fsetを使って(マクロとして)Lispでdefunを書くことができる。

これらの使用例を示す。

;; fooの定義をold-fooに保存する
(fset 'old-foo (symbol-function 'foo))

;; シンボルcarxfirstの関数定義にする
;; (これには、fsetよりdefaliasのほうがよい)
(fset 'xfirst 'car)
     => car
(xfirst '(1 2 3))
     => 1
(symbol-function 'xfirst)
     => car
(symbol-function (symbol-function 'xfirst))
     => #<subr car>

;; 名前付きのキーボードマクロを定義する
(fset 'kill-two-lines "\^u2\^k")
     => "\^u2\^k"

;; 他の関数を変更する関数
(defun copy-function-definition (new old)
  "Define NEW with the same function definition as OLD."
  (fset new (symbol-function old)))

既存の関数定義を拡張する関数を書くときには、 つぎのような常套句を使うこともあります。

(fset 'old-foo (symbol-function 'foo))
(defun foo ()
  "Just like old-foo, except more so."
  (old-foo)
  (more-so))

fooが自動ロードと定義されていると、これは正しく動作しません。 そのような場合には、fooold-fooを呼び出すと、 Lispはファイルをロードしてold-fooを定義しようとします。 しかし、これはold-fooではなくfooを定義するので、 正しい結果を得られません。 この問題を回避する唯一の方法は、 fooの古い定義を移すまえに、確実にファイルをロードしておくことです。

しかし、別の箇所で定義された関数を再定義するLispファイルに対しては、 いずれにしても、これではモジュール化も見通しもよくありません。 アドバイズ機能(see Advising Functions)を使えば、見通しがよくなります。


Node:Inline Functions, Next:, Previous:Function Cells, Up:Functions

インライン関数

defunのかわりにdefsubstを使うことで、 インライン関数(inline function)を定義できます。 インライン関数は、1つの点を除いて、普通の関数と同様に動作します。 そのような関数の呼び出しをコンパイルすると、 関数定義は呼び出し側で展開されます。

関数を展開すると明示的な呼び出しが高速になります。 しかし、それには欠点もあります。 その1つは、柔軟性を減らすことです。 関数の定義を変更しても、コンパイルし直すまでは、 すでに展開された呼び出しは古い定義を使い続けます。 関数を再定義できる柔軟性はEmacsでは重要な機能ですから、 速度が本当に重要でなければ、関数を展開すべきではありません。

別の欠点は、大きな関数を展開すると、コンパイルした関数のサイズが ファイル内でもメモリ上でも増加します。 インライン関数のスピードの利点は、小さな関数でもっとも大きいので、 一般には大きな関数を展開すべきではありません。

インライン関数が実行するのと同じコードに展開するようにマクロを定義する ことも可能です。 (see Macros。) しかし、マクロは式で直接使った場合に制限されます。 マクロは、applymapcarなどで呼び出せません。 さらに、普通の関数をマクロに変換するには、多少の作業が必要です。 普通の関数をインライン関数に変換するのはとても簡単です。 単に、defundefsubstで置き換えるだけです。 インライン関数の各引数は、ちょうど1回だけ評価されるので、 マクロのように本体で引数を何回使うかを考慮する必要はありません。 (see Argument Evaluation。)

インライン関数は、マクロと同様に、 同じファイル内の定義位置よりうしろで使われ展開されます。


Node:Related Topics, Previous:Inline Functions, Up:Functions

関数に関連したその他の話題

関数呼び出しと関数定義に関連したいくつかの関数の一覧をあげておきます。 これらは別の場所で説明してありますが、相互参照をあげておきます。

apply
see Calling Functions
autoload
see Autoload
call-interactively
see Interactive Call
commandp
see Interactive Call
documentation
see Accessing Documentation
eval
see Eval
funcall
see Calling Functions
function
see Anonymous Functions
ignore
see Calling Functions
indirect-function
see Function Indirection
interactive
see Using Interactive
interactive-p
see Interactive Call
mapatoms
see Creating Symbols
mapcar
see Mapping Functions
map-char-table
see Char-Tables
mapconcat
see Mapping Functions
undefined
see Key Lookup


Node:Macros, Next:, Previous:Functions, Up:Top

マクロ

マクロ(macros)により、 新たな制御構造の構文を定義したり、他の言語の機能を定義したりできます。 マクロは関数のように定義しますが、値の計算方法を指示するかわりに、 値を計算するための別のLisp式の計算方法を指示します。 この式をマクロの展開形(expansion)と呼びます。

マクロでこのようなことができるのは、 関数が評価済みの引数を操作するのに対して、 マクロは引数の未評価の式を操作するからです。 そのため、これらの引数の式やその一部を含む展開形を構築できるのです。

実行速度のために普通の関数でできることにマクロを使うのであれば、 そのかわりにインライン関数を使うことを考えてください。


Node:Simple Macro, Next:, Up:Macros

マクロの簡単な例

C言語の演算子++のように、 変数の値を増加させるLispの構文を定義したいとしましょう。 (inc x)のように書いて、 (setq x (1+ x))のような効果を得たいのです。 これを行うマクロ定義はつぎのようになります。

(defmacro inc (var)
   (list 'setq var (list '1+ var)))

これを(inc x)のように呼び出すと、 引数varはシンボルxになります。 関数のようにxではありません。 マクロの本体では、これを使って展開形(setq x (1+ x))を構築します。 マクロ定義がこの展開形を返すと、 Lispはそれを評価することに進み、xを増やします。


Node:Expansion, Next:, Previous:Simple Macro, Up:Macros

マクロ呼び出しの展開

マクロ呼び出しはマクロ名で始まるリストであり、 関数呼び出しとほとんど同じに見えます。 リストの残りの要素はマクロの引数です。

マクロ呼び出しの評価は、関数呼び出しの評価のように始められますが、 1つだけ重要な違いがあります。 マクロの引数は、マクロ呼び出しに現れた実際の引数です。 マクロ定義に渡すまえに、それらを評価しません。 一方、関数の引数は、関数呼び出しのリストの要素を評価した結果です。

引数を得ると、Lispは関数定義を起動するのと同様にマクロ定義を起動します。 マクロの引数変数は、マクロ呼び出しの引数値や &rest引数の場合にはそれらのリストに束縛されます。 そうして、マクロ本体を実行し、関数本体と同様に値を返します。

マクロと関数の重要な違いの2つめは、 マクロ本体が返した値はマクロ呼び出しの値ではないことです。 戻り値は値を計算するためのかわりの式であり、 これをマクロの展開形(expansion)といいます。 Lispインタープリタは、マクロから戻ってくると、 ただちに展開形を評価することへ進みます。

展開形は、通常どおりに評価されるので、 展開形から他のマクロを呼び出してもかまいません。 同一のマクロを呼び出してもかまいませんが、 それは一般的ではありません。

macroexpandを呼ぶと、指定したマクロの展開形を調べることができます。

macroexpand form &optional environment Function
この関数は、formがマクロ呼び出しならば、それを展開する。 その結果がまた別のマクロ呼び出しであれば、さらに展開する。 マクロ呼び出しでない結果を得るまでこれを繰り返す。 それが、macroexpandが返す値である。 formが始めからマクロ呼び出しでなければ、 与えられたとおりのものを返す。

macroexpandformの部分式を調べないことに注意してほしい (ただし、マクロ定義によっては調べるかもしれない)。 部分式がマクロ呼び出しであったとしても、 macroexpandはそれらを展開しない。

関数macroexpandは、インライン関数の呼び出しは展開しない。 インライン関数の呼び出しを理解することは普通の関数呼び出しを理解するのと かわりないので、通常、そのような展開を行う必要はない。

environmentを指定すると、 それは、現在定義済みのマクロを隠すマクロ定義の連想リストを表す。 バイトコンパイルではこの機能を使う。

(defmacro inc (var)
    (list 'setq var (list '1+ var)))
     => inc

(macroexpand '(inc r))
     => (setq r (1+ r))

(defmacro inc2 (var1 var2)
    (list 'progn (list 'inc var1) (list 'inc var2)))
     => inc2

(macroexpand '(inc2 r s))
     => (progn (inc r) (inc s))  ; ここではincを展開しない


Node:Compiling Macros, Next:, Previous:Expansion, Up:Macros

マクロとバイトコンパイル

なぜ、マクロの展開形をわざわざ計算してから展開形を評価するのか、 疑問に思うかもしれません。 なぜ、マクロ本体で望みの結果を直接出さないのでしょう? その理由には、コンパイルが関係しています。

コンパイルするLispプログラムにマクロ呼び出しが現れると、 Lispコンパイラは、インタープリタがするのと同様にマクロ定義を呼び出し、 その展開形を受け取ります。 この展開形を評価するかわりに、コンパイラは、 展開形がプログラムに直接現れたかのようにそれをコンパイルします。 その結果、コンパイル済みのコードは、マクロが意図した値と副作用を生じ、 かつ、実行速度はコンパイルした速度になるのです。 マクロ本体そのもので値と副作用を計算したのでは、 このように動作しません。 コンパイル時に計算してしまい、それでは意味がありません。

マクロ呼び出しが正しくコンパイルされるためには、 それらの呼び出しをコンパイルするときに、 Lisp内でマクロが定義済みである必要があります。 コンパイラには、読者がこのようにすることを補佐する機能があります。 コンパイル対象のファイルにフォームdefmacroが含まれていると、 そのファイルの残りをコンパイルするあいだは、 一時的にマクロを定義します。 この機能が動作するためには、 defmacroを同じファイルの最初に利用する箇所よりまえに 入れておく必要があります。

ファイルをバイトコンパイルすると、 そのファイルのトップレベルにあるrequireの呼び出しを実行します。 これは、ファイルを正しくコンパイルするために必要なパッケージを表します。 コンパイル中に必要なマクロ定義が使えることを保証する1つの方法は、 それらのマクロを定義するファイルを requireに指定しておくことです(see Named Features)。 コンパイル済みのプログラムを実行するときに、 マクロを定義したファイルをロードしてしまうことを避けるには、 requireの呼び出しの周りにeval-when-compileを書いておきます (see Eval During Compile)。


Node:Defining Macros, Next:, Previous:Compiling Macros, Up:Macros

マクロ定義

Lispのマクロは、そのCARmacroであるリストです。 そのCDRは関数であるべきです。 マクロの展開は、マクロ呼び出しの未評価の引数式に (applyで)関数を適用して動作します。

無名関数のように無名Lispマクロを使うことも可能ですが、 けっしてしないでしょう。 mapcarのようなファンクショナルに無名マクロを渡す意味がないからです。 実用上は、すべてのLispマクロには名前があり、 普通、スペシャルフォームdefmacroで定義します。

defmacro name argument-list body-forms... Special Form
defmacroは、シンボルnameをつぎのようなマクロとして定義する。
(macro lambda argument-list . body-forms)

(このリストのCDRは関数、つまり、ラムダ式であることに注意。) このマクロオブジェクトは、nameの関数セルに格納される。 フォームdefmacroを評価した結果、返される値はnameであるが、 通常この値は無視する。

argument-listの形式と意味は、関数のそれと同じであり、 キーワード&rest&optionalを使ってもよい (see Argument List)。 マクロにも説明文字列を指定できるが、 マクロを対話的に呼び出すことはできないので、 interactive宣言は無視する。


Node:Backquote, Next:, Previous:Defining Macros, Up:Macros

バッククォート

マクロでは、定数部分と非定数部分を組み合わせた大きなリスト構造を 構築する必要がしばしばあります。 これを簡単に行うためには、 (通常、バッククォート(backquote)と呼ばれる)`構文を 使います。

バッククォートにより、リストの要素を選択に評価しつつ、 リストをクォートできます。 もっとも単純な場合、これはスペシャルフォームquote(see Quoting)と 等価です。 たとえば、つぎの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)

バッククォートの引数の内側にある特別な印,は、 値が定数ではないことを表します。 バッククォートは、リスト構造の中の,の引数を評価し、 値で置き換えます。

(list 'a 'list 'of (+ 2 3) 'elements)
     => (a list of 5 elements)
`(a list of ,(+ 2 3) elements)
     => (a list of 5 elements)

,による置き換えは、リスト構造の深いレベルでも許されます。 たとえば、つぎのとおりです。

(defmacro t-becomes-nil (variable)
  `(if (eq ,variable t)
       (setq ,variable nil)))

(t-becomes-nil foo)
     == (if (eq foo t) (setq foo nil))

特別な印,@を使って、 評価結果を結果となるリストに繋ぎ合わせる(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)

19.29版よりまえのEmacsの旧版では、 `の構文は異なっていて、 バッククォート構文全体を囲む括弧の余分なレベルが必要でした。 同様に、,,@の置換でも、 ,,@、および後続の式を囲む括弧の余分なレベルが1つ必要でした。 古い構文では、`,,@と後続の式とのあいだには 空白が必要でした。

この構文も受け付けますが、これはEmacsの旧版との互換性のためであり、 新しいプログラムでは使わないことを勧めます。


Node:Problems with Macros, Previous:Backquote, Up:Macros

マクロ使用時の一般的な問題

マクロ展開に関する基本的事実には、直観的でない結果があります。 本節では、問題を引き起こしかねない重要な結果を説明し、 問題を回避するための規則を説明します。


Node:Argument Evaluation, Next:, Up:Problems with Macros

マクロ引数の複数回評価

マクロを定義するときには、展開形を実行するときに、 引数が何回評価かされるかに注意を払う必要があります。 つぎの(繰り返しを行う)マクロで、この問題を示しましょう。 このマクロで、Pascalにあるような単純な『for』ループを書けます。

(defmacro for (var from init to final do &rest body)
  "Execute a simple \"for\" loop.
For example, (for i from 1 to 10 do (print i))."
  (list 'let (list (list var init))
        (cons 'while (cons (list '<= var final)
                           (append body (list (list 'inc var)))))))
=> for

(for i from 1 to 3 do
   (setq square (* i i))
   (princ (format "\n%d %d" i square)))
==>
(let ((i 1))
  (while (<= i 3)
    (setq square (* i i))
    (princ (format "%d      %d" i square))
    (inc i)))

     -|1       1
     -|2       4
     -|3       9
=> nil

このマクロの引数、fromtodoは、 『シンタックスシュガー』であり、完全に無視します。 (fromtodoなどの)余分な単語を マクロ呼び出しのこの引数位置に書けるようにするのです。

バッククォートを使って単純化した等価な定義をつぎに示します。

(defmacro for (var from init to final do &rest body)
  "Execute a simple \"for\" loop.
For example, (for i from 1 to 10 do (print i))."
  `(let ((,var ,init))
     (while (<= ,var ,final)
       ,@body
       (inc ,var))))

この定義の(バッククォートありとなしの)どちらの形式でも、 各繰り返しごとにfinalが評価されるという欠陥があります。 finalが定数ならば、これは問題になりません。 たとえば(long-complex-calculation x)のような、 より複雑なフォームであると、実行速度をかなり遅くしてしまいます。 finalに副作用があると、複数回評価するのは正しくありません。

繰り返し評価することがマクロの意図している目的の一部でなければ、 よく設計されたマクロ定義では、 引数をちょうど1回だけ評価するような展開形を生成して、 上のような問題を回避するように手立てします。

(let ((i 1)
      (max 3))
  (while (<= i max)
    (setq square (* i i))
    (princ (format "%d      %d" i square))
    (inc i)))

このような展開形を作るマクロ定義はつぎのようになります。

(defmacro for (var from init to final do &rest body)
  "Execute a simple for loop: (for i from 1 to 10 do (print i))."
  `(let ((,var ,init)
         (max ,final))
     (while (<= ,var max)
       ,@body
       (inc ,var))))

残念なことに、この修正は、 次節に説明する別の問題を引き起こします。


Node:Surprising Local Vars, Next:, Previous:Argument Evaluation, Up:Problems with Macros

マクロ展開形内のローカル変数

forの新しい定義には、新たな問題があります。 ユーザーが予期していないローカル変数maxを導入しているのです。 これは、つぎのような場合、問題を引き起こします。

(let ((max 0))
  (for x from 0 to 10 do
    (let ((this (frob x)))
      (if (< max this)
          (setq max this)))))

forの本体内でのmaxの参照は、 ユーザーが束縛したmaxを参照するものと期待されていますが、 実際にはforが作った束縛を使います。

これを修正するには、maxのかわりに、 インターンしてないシンボル(see Creating Symbols)を使います。 インターンしてないシンボルは、他のシンボルと同様に、 束縛したり参照したりできますが、forで作ったので、 ユーザープログラムには現れていないことがわかっています。 インターンしてないので、ユーザーがプログラムのあとの部分で 参照する方法もありません。 forで使った箇所以外には現れえないのです。 このように動作するforの定義をつぎに示します。

(defmacro for (var from init to final do &rest body)
  "Execute a simple for loop: (for i from 1 to 10 do (print i))."
  (let ((tempvar (make-symbol "max")))
    `(let ((,var ,init)
           (,tempvar ,final))
       (while (<= ,var ,tempvar)
         ,@body
         (inc ,var)))))

これは、maxという名前のインターンしてないシンボルを作成し、 もとの式に現れていたインターンしたシンボルmaxのかわりに 展開形内部で使います。


Node:Eval During Expansion, Next:, Previous:Surprising Local Vars, Up:Problems with Macros

展開形におけるマクロ引数の評価

eval(see Eval)を呼び出すなどして、 マクロ定義そのものの中でマクロ引数の式を評価すると、 別の問題を生じます。 引数でユーザーの変数を参照する場合、 ユーザーがマクロ引数の1つと同じ名前を使っていると、 問題になります。 マクロ本体の内側では、マクロ引数の束縛が最ローカルな束縛ですから、 そのフォームの内側からの参照は、この束縛を使います。 例を示しましょう。

(defmacro foo (a)
  (list 'setq (eval a) t))
     => foo
(setq x 'b)
(foo x) ==> (setq b t)
     => t                  ; bを設定する
;; しかし
(setq a 'c)
(foo a) ==> (setq a t)
     => t                  ; cではなくaを設定する

ユーザーの引数の名前がaxかで違いがでます。 というのは、マクロ引数の変数aaが衝突するからです。

マクロ定義内でevalを呼び出したときの別の問題点は、 コンパイルしたプログラムでは、意図した動作をしないだろうということです。 バイトコンパイラは、プログラムをコンパイル中にマクロ定義を実行しますから、 (evalで参照したい)プログラムそのものの計算は行われず、 そのローカル変数の束縛も存在しません。

これらの問題を回避するには、 マクロ展開の計算過程では、引数の式を評価しないことです。 そのかわりに、マクロ展開では式の置換を使って、 展開時にその値が計算されるようにします。 このようにすれば、本章の他の例題は動作します。


Node:Repeated Expansion, Previous:Eval During Expansion, Up:Problems with Macros

マクロは何回展開されるか

関数を解釈実行しているときには、マクロ呼び出しを評価するたびに展開しますが、 コンパイルした関数では、(コンパイル時に)1回だけ展開します。 この違いが問題になることもあります。 マクロ定義に副作用があると、 マクロを何回展開したかに依存して動作が異なります。

したがって、マクロ展開の計算では、 本当になにをしているのか理解していない限り、副作用は避けてください。

特別な種類の副作用の1つ、つまり、 Lispオブジェクトを構築することは回避できません。 ほとんどすべてのマクロ展開では、リストを構築し、 それがマクロの重要な点でもあります。 これは、通常、安全ですが、 1つだけ注意する必要があります。 読者が構築したオブジェクトが、 マクロ展開形の中のクォートした定数の一部であるときです。

コンパイル時にマクロを1回だけ展開すると、 コンパイル中にはオブジェクトは一度だけ作られます。 しかし、解釈実行中には、マクロ呼び出しを行うたびにマクロを展開するので、 そのたびに新たなオブジェクトが作成されたことを意味します。

見通しのよいほとんどのLispコードでは、この違いは関係ありません。 マクロ定義で構築したオブジェクトに副作用のある操作を行うと 違いが出てきます。 したがって、問題を回避するには、 マクロ定義で構築したオブジェクトに副作用のある操作は行わない ということです。 そのような副作用がどのように問題を引き起こすのか、例をあげましょう。

(defmacro empty-object ()
  (list 'quote (cons nil nil)))

(defun initialize (condition)
  (let ((object (empty-object)))
    (if condition
        (setcar object condition))
    object))

initializeを解釈実行しているときには、 initializeを呼び出すたびに新たなリスト(nil)が作られます。 したがって、2つの呼び出しのあいだで副作用が残ることはありません。 initializeをコンパイルしてあると、 マクロempty-objectはコンパイル時に展開され、 1つの『定数』(nil)を作りますが、 これは、initializeを呼び出すたびに、 再利用され変更されてしまいます。

このような病的な場面を回避する1つの方法は、 empty-objectを、メモリ割り付けではなく、 ある種の定数と考えることです。 '(nil)のような定数にsetcarは使わないでしょうから、 (empty-object)も自然にそのように使わないでしょう。


Node:Customization, Next:, Previous:Macros, Up:Top

カスタマイズ定義の書き方

本章では、カスタマイズのためのユーザーオプションの宣言方法、 および、それらを分類するカスタマイズグループの宣言方法を説明します。 フェイスの定義(see Defining Faces)に加えて、 カスタマイズの両方の種類を含めて、 カスタマイズ項目(customization item)という用語を使います。


Node:Common Keywords, Next:, Up:Customization

すべての種類の項目に共通のキーワード

(変数やグループ、フェイスの)すべての種類のカスタマイズ宣言では、 さまざまな情報を指定するためのキーワード引数を受け付けます。 本節では、全種類に適用できるキーワードを説明します。

:tagを除くこれらのキーワードすべては、各項目で複数回使えます。 キーワードのそれぞれの使用には、独立の効果があります。 キーワード:tagは例外です。 任意の項目には名前を1つしか表示できないからです。

:tag name
カスタマイズメニューやカスタマイズバッファ内で 項目に付けるラベルとして、項目の名前のかわりに文字列nameを使う。
:group group
このカスタマイズ項目をグループgroupに入れる。 defgroupの中で:groupを使うと、 新たなグループをgroupの下位グループにする。

このキーワードを複数回使うと、 1つの項目を複数のグループに入れることができる。 それらのグループのどれを表示しても、この項目が表示される。 これを多用しすぎないように注意すること!

:link link-data
この項目に対する説明文字列のうしろに外部リンクを含める。 これは、他の説明文字列を参照するアクティブフィールドを含む文である。

link-dataとして使えるものは3種類ある。

(custom-manual info-node)
infoのノードへリンクする。 info-nodeは、"(emacs)Top"のようなノード名を指定する文字列。 リンクは、カスタマイズバッファでは[manual]のように表示される。
(info-link info-node)
custom-manualと同様であるが、 カスタマイズバッファに現れるリンクはinfoのノード名になる。
(url-link url)
webページへリンクする。 urlは、URLを指定する文字列。 カスタマイズバッファに現れるリンクはurlになる。

link-dataの先頭要素のうしろに:tag nameを使うことで、 カスタマイズバッファに使うテキストを指定できる。 たとえば、(info-link :tag "foo" "(emacs)Top")とすると、 バッファではfooと表示されるEmacsマニュアルへのリンクを作れる。

1つの項目に複数個の外部リンクがあってもよいが、 ほとんどの項目には外部リンクはない。

:load file
このカスタマイズ項目を表示するまえにファイルfile(文字列)をロードする。 ファイルをすでにロードしていない場合に限り、 load-libraryでロードする。
:require feature
カスタマイズ機能を用いて保存するこの項目に対する値をインストールするときに 必要となる機能feature(シンボル)を指定する。 requireを呼び出す。

:requireを使うもっとも一般的な理由は、 変数がマイナモードなどの機能をオンにするとき、 そのモードを実装するコードをロードしてないと、 変数にはなんの効果もないからである。


Node:Group Definitions, Next:, Previous:Common Keywords, Up:Customization

カスタマイズグループを定義する

Emacs Lispの各パッケージには、 そのパッケージのすべてのオプション、フェイス、他のグループを含んだ 1つの主要なカスタマイズグループがあるべきです。 パッケージに少数のオプションやフェイスしかなければ、 それらを1つのグループにまとめます。 12個を超えるオプションやフェイスがある場合には、 それらを下位グループに構造化して、 下位グループすべてをパッケージの主カスタマイズグループに入れておきます。 パッケージの主グループに下位グループとともにいくつかのオプションやフェイスを 入れておくのもよいでしょう。

パッケージの主グループや単一のグループは、 標準カスタマイズグループの1つかそれ以上のメンバであるべきです。 (それらの完全な一覧を表示するにはM-x customizeを使う。) それらの中から1個か数個を選び(多すぎないこと)、 キーワード:groupを使って、それぞれに読者のグループを追加します。

新たなカスタマイズグループは、defgroupで宣言します。

defgroup group members doc [keyword value]... Macro
membersを含むカスタマイズグループとしてgroupを宣言する。 シンボルgroupをクォートしないこと。 引数docは、グループの説明文字列を指定する。

引数membersは、グループのメンバとなる カスタマイズ項目の初期集合を指定するリストである。 しかし、ほとんどの場合、membersnilであり、 それらのメンバを定義するときに、キーワード:groupを使って、 グループのメンバであることを指定する。

membersでグループのメンバを指定する場合には、 各要素は(name widget)という形式であること。 ここで、nameはシンボル、 widgetはそのシンボルを編集するためのウィジェット型である。 有用なウィジェットは、変数に対してはcustom-variable、 フェイスに対してはcustom-face、 グループに対してはcustom-groupである。

共通のキーワード(see Common Keywords)に加えて、 defgroupではつぎのキーワードも使える。

:prefix prefix
グループ内の項目の名前がprefixで始まるときには、 その項目に対するタグを(デフォルトでは)prefixを省略して作る。

1つのグループにprefixがいくつあってもよい。

接頭辞を取りさる機能は、現在、オフにしてあります。 つまり、:prefixは、現在、なんの効果もありません。 このようにしたのは、指定した接頭辞を取りさると、 オプション名がしばしば混乱するからです。 さまざまなグループのdefgroup定義を書く人は、 論理的と考えられるとき、つまり、ライブラリに共通の接頭辞があるときには キーワード:prefixを追加するので、このようになるのです。

:prefixを使ってよい結果を得るには、 グループ内の特定の項目とそれらの名前と説明文字列に関して、 特定の接頭辞を取りさった場合の効果を調べる必要があります。 その結果、テキストがわかり難ければ、 その場面では、:prefixを使うべきではないのでしょう。

カスタマイズグループすべてを調べ直して、 わかり難くなる結果をもたらす:prefix指定を削除し、 この機能をオンにすることは、誰かが頑張れば、可能です。


Node:Variable Definitions, Next:, Previous:Group Definitions, Up:Customization

カスタマイズ変数を定義する

defcustomを使って、ユーザーが編集可能な変数を宣言します。

defcustom option default doc [keyword value]... Macro
カスタマイズ可能なユーザーオプション変数としてoptionを宣言する。 optionをクォートしないこと。 引数docは変数の説明文字列を指定する。

optionが空であると、defcustomdefaultで初期化する。 defaultは値を計算する式であること。 これは複数回評価される可能性があるので、書き方には注意すること。

defcustomでは、つぎの追加キーワードも使えます。

:type type
このオプションのデータ型としてtypeを使う。 これは、正しい値とその表示方法を指定する。 詳しくは、see Customization Types
:options list
このオプションに使える合理的な値のリストとしてlistを指定する。

これは、現時点では、型がhookのときだけ意味を持つ。 その場合、listの要素は、フックの値の要素として使える関数であること。 ユーザーはこれらの関数以外も使えるが、便利な選択肢として提示する。

:version version
このオプションは、変数を最初に導入したり、デフォルト値を変更したりした Emacsの版versionを指定する。 値versionは、文字列であること。 たとえば、つぎのとおり。
(defcustom foo-max 34
  "*Maximum number of foo's allowed."
  :type 'integer
  :group 'foo
  :version "20.3")

:set setfunction
このオプションの値を変更する方法としてsetfunctionを指定する。 関数setfunctionは、2つの引数、つまり、シンボルと新しい値を取り、 このオプションの値を(Lisp変数としてオプションを設定するだけでなく) 適切に更新するために必要なことを行うこと。 setfunctionのデフォルトはset-default
:get getfunction
このオプションの値を取り出す方法としてgetfunctionを指定する。 関数getfunctionは、1つの引数、つまり、シンボルを取り、 そのシンボル(のLisp値とは必ずしも限らない)の『現在値』を返すこと。 デフォルトはdefault-value
:initialize function
functionは、defcustomを評価したときに変数の初期化に使う関数。 この関数は、2つの引数、つまり、シンボルと値を取ること。 このように使うことを意図した定義済みの関数がいくつかある。
custom-initialize-set
変数の:set関数を使って変数を初期化するが、 変数の値が空でないときには再初期化しない。 これは:initializeのデフォルト。
custom-initialize-default
custom-initialize-setに似ているが、 変数の:set関数のかわりに関数set-defaultを使って変数を設定する。 変数の:set関数がマイナモードをオン/オフする場合には、 普通はこれを選ぶ。 これを選ぶと、変数を定義してもマイナモード関数を呼び出さないが、 変数をカスタマイズするとマイナモード関数を呼び出す。
custom-initialize-reset
変数を初期化するにはつねに:set関数を使う。 変数の値が空でない場合には、(:getで得られる)現在値で :set関数を呼び出して、変数をリセットする。
custom-initialize-changed
変数がすでに設定されていたりカスタマイズしてあるときに、 変数を初期化するために:set関数を使う。 さもなければ、set-defaultを使う。

:requireオプションは、 特定の機能をオンにするようなオプションには便利です。 パッケージがオプション変数の値を検査するように書かれていたとしても、 パッケージをロードするようにする必要があります。 これを:requireで行えるのです。 See Common Keywords。 ライブラリparen.elからとった例をつぎに示します。

(defcustom show-paren-mode nil
  "Toggle Show Paren mode...."
  :set (lambda (symbol value)
         (show-paren-mode (or value 0)))
  :initialize 'custom-initialize-default
  :type 'boolean
  :group 'paren-showing
  :require 'paren)

内部的には、defcustomは、 デフォルト値を与える式は属性standard-valueを使って記録し、 ユーザーがカスタマイズバッファで保存した値は 属性saved-valueを使って記録しています。 属性saved-valueは実際にはリストであり、 そのCARが値に評価される式です。


Node:Customization Types, Previous:Variable Definitions, Up:Customization

カスタマイズ型

defcustomでユーザーオプションを定義するときには、 そのカスタマイズ型(customization type)を定義する必要があります。 これはLispオブジェクトであり、 (1)どのような値が正しいものであり、 (2)編集用にカスタマイズバッファに表示する方法、 を示します。

カスタマイズ型は、defcustom内の:typeキーワードで指定します。 :typeの引数は評価されます。 実行時に型が変わるものはほとんど使い途がないので、 普通、クォートした型を指定します。 たとえば、つぎのとおりです。

(defcustom diff-command "diff"
  "*The command to use to run diff."
  :type '(string)
  :group 'diff)

一般に、カスタマイズ型はリストであり、 その先頭要素はシンボルで、次節以降で定義するカスタマイズ型名の1つです。 このシンボルのあとには、シンボルに依存した数個の引数が続きます。 型シンボルとその引数のあいだには、 キーワード・値の対を書くこともできます (see Type Keywords)。

型シンボルには、引数を取らないものもあります。 これらを単純型(simple types)と呼びます。 単純型では、キーワード・値の対を指定しなければ、 型シンボルを囲む括弧を省略できます。 たとえば、カスタマイズ型としてのstringは、 (string)と等価です。


Node:Simple Types, Next:, Up:Customization Types

単純型

本節では、すべての単純型を説明します。

sexp
値は、表示したり読み取れるならば、任意のLispオブジェクトでよい。 使用する型をより限定する手間を省きたければ、 任意のオプションに対するデフォルトとして、 sexpを使うことができる。
integer
値は整数である必要があり、カスタマイズバッファではテキストで表示する。
number
値は数である必要があり、カスタマイズバッファではテキストで表示する。
string
値は文字列である必要があり、 カスタマイズバッファでは、その内容だけを表示し、 文字"で区切ったり、\でクォートしない。
regexp
stringと同様であるが、 文字列は正規表現である必要がある。
character
値は文字コードである必要がある。 文字コードは実際には整数であるが、 この型では、数として表示するのではなく、 文字としてバッファに挿入してその値を表示する。
file
値はファイル名である必要があり、M-<TAB>で補完できる。
(file :must-match t)
値は既存のファイル名である必要があり、M-<TAB>で補完できる。
directory
値はディレクトリ名である必要があり、M-<TAB>で補完できる。
hook
値は関数のリスト(あるいは、単一の関数。ただし、この使い方は廃れている) である必要がある。 このカスタマイズ型は、フック変数に使用する。 フックに使う推奨される関数のリストを指定するために、 フック変数のdefcustom:optionsキーワードを使用できる。 see Variable Definitions
symbol
値はシンボルである必要がある。 カスタマイズバッファでは、シンボルの名前を表示する。
function
値はラムダ式か関数名である必要がある。 関数名の場合、M-<TAB>で補完できる。
variable
値は変数名である必要があり、M-<TAB>で補完できる。
face
値はフェイス名を表すシンボルである必要があり、M-<TAB>で補完できる。
boolean
値は真理値、つまり、niltである必要がある。 choiceconstを同時に使うと(次節参照)、 値はniltである必要があることを指定し、 さらに、どちらの値がどの選択肢に合うかを記述するテキストを 指定できることに注意。


Node:Composite Types, Next:, Previous:Simple Types, Up:Customization Types

複合型

単純型が適切でない場合には、 他の型から新たな型を作り上げる複合型を使えます。 これには、いくつかの方法があります。

(restricted-sexp :match-alternatives criteria)
値は、criteriaの1つを満たす任意のLispオブジェクトでよい。 criteriaはリストであり、その各要素は以下の1つであること。

たとえば、

(restricted-sexp :match-alternatives
                 (integerp 't 'nil))

は、整数、tnilが正しい値である。

カスタマイズバッファでは、すべての正しい値はその入力構文で表示し、 ユーザーはそれらをテキストとして編集する。

(cons car-type cdr-type)
値はコンスセルである必要があり、 そのCARcar-typeに合い、かつ、 そのCDRcdr-typeに合う必要がある。 たとえば、(cons string symbol)は、 ("foo" . foo)などの値に一致するカスタマイズ型である。

カスタマイズバッファでは、 CARCDRは、 それらに指定した型に応じて別々に表示され、個別に編集できる。

(list element-types...)
値はelement-typesに指定したとおりの個数のリストである必要があり、 各要素はelement-typeに合うこと。

たとえば、(list integer string function)は、 3要素のリストを意味し、 第1要素は整数、第2要素は文字列、第3要素は関数であることを指定する。

カスタマイズバッファでは、 各要素は、それらに指定した型に応じて別々に表示され、個別に編集できる。

(vector element-types...)
listと同様だが、値はリストではなくベクトルである必要がある。 その要素はlistの場合と同じ。
(choice alternative-types...)
値は、alternative-typesの少なくとも1つに合う必要がある。 たとえば、(choice integer string)は、整数か文字列を許す。

カスタマイズバッファでは、ユーザーはメニューを使って選択肢を選び、 その選択肢において普通の方法で値を編集する。

通常、このメニューの選択肢名は、選択肢から自動的に決定されるが、 選択肢に:tagキーワードを含めることで、 メニューに異なる名前を指定できる。 たとえば、整数が空白の個数を表し、文字列がそのまま使うテキストを表す場合には、 つぎのようにカスタマイズ型を書く。

(choice (integer :tag "Number of spaces")
        (string :tag "Literal text"))

そうすると、メニューには、 Number of spacesLiteral Textが表示される。

const以外のnilが正当な値ではない選択肢では、 そのような選択肢には:valueキーワードを使って 正当なデフォルト値を指定すること。 See Type Keywords

(const value)
値はvalueであること。 それ以外は許さない。

constの主な用途はchoiceの内側である。 たとえば、(choice integer (const nil))は、整数かnilを許す。

choiceの内側では、constにしばしば:tagを使う。 たとえば、

(choice (const :tag "Yes" t)
        (const :tag "No" nil)
        (const :tag "Ask" foo))

は、tは『yes』(はい)、nilは『no』(いいえ)、 fooは『ask』(問い合わせる)を意味する変数を記述する。

(other value)
この選択肢は任意のLisp値に一致するが、 ユーザーがこの選択肢を選ぶと、値valueを選ぶことになる。

otherは、主に、choiceの最後の要素として使うことである。 たとえば、

(choice (const :tag "Yes" t)
        (const :tag "No" nil)
        (other :tag "Ask" foo))

は、tは『yes』(はい)、nilは『no』(いいえ)、 それ以外は『ask』(問い合わせる)を意味することを示す。 ユーザーが選択肢のメニューからAskを選ぶと、値fooを指定する。 しかし、(tでもnilでもfooでもない)それ以外の値は、 fooと同様にAskと表示される。

(function-item function)
constと同様だが、関数であるような値に使う。 これは、関数名に加えて説明文字列を表示する。 説明文字列は、:docに指定したものか、 functionそのものの説明文字列である。
(variable-item variable)
constと同様だが、変数名であるような値に使う。 これは、変数名に加えて説明文字列を表示する。 説明文字列は、:docに指定したものか、 variableそのものの説明文字列である。
(set elements...)
値はリストである必要があり、 その各要素はelementsに指定したものの1つである必要がある。 これは、カスタマイズバッファにはチェックリストとして表示される。
(repeat element-type)
値はリストである必要があり、 その各要素はelement-typeに指定した型に合う必要がある。 これは、カスタマイズバッファには、 要素を追加したり削除したりする[INS][DEL]ボタンを伴って、 要素のリストとして表示される。


Node:Splicing into Lists, Next:, Previous:Composite Types, Up:Customization Types

リストに繋ぎ合わせる

:inline機能により、可変個数の要素をリストやベクトルの 途中に繋ぎ合わせることができます。 listvectorの要素型に現れる set型、choice型、repeat型の中に使います。

通常、listvectorのおのおのの要素型は、 リストやベクトルのたった1つの要素を記述します。 したがって、要素型がrepeatであると、 1要素として表示される長さを指定しないリストを指定します。

しかし、要素型に:inlineを使うと、 これに一致する値は、:inlineを含むシーケンスに直接に併合されます。 たとえば、3要素のリストに一致すると、 それがシーケンス全体の3つの要素になります。 これはバッククォート構文の,@の使い方に似ています。

たとえば、先頭要素がtであり、 残りがfoobarの0個以上の繰り返しであるリストを指定するには、 つぎのカスタマイズ型を使います。

(list (const t) (set :inline t foo bar))

これは、(t)(t foo)(t bar)(t foo bar)などの 値に一致します。

要素型がchoiceであるときには、 choiceそのものには:inlineを使いませんが、 choiceの選択肢(のどれか)に:inlineを使います。 たとえば、ファイル名で始まりシンボルtか2つの文字列が続くような リストに一致するようにするには、 つぎのカスタマイズ型を使います。

(list file
      (choice (const t)
              (list :inline t string string)))

ユーザーが最初の選択肢を選ぶと、全体としてのリストは2要素になり、 第2要素はtです。 ユーザーが2番目の選択肢を選ぶと、 全体としてのリストは3要素になり、 第2要素と第3要素は文字列である必要があります。


Node:Type Keywords, Previous:Splicing into Lists, Up:Customization Types

型キーワード

型名のシンボルのあとに、カスタマイズ型内にキーワード・引数の対を指定できます。 使えるキーワードとその意味を以下に示します。

:value default
choiceの内側の選択肢として現れる型に使う。 これは、カスタマイズバッファのメニューでユーザーがこの選択肢を選ぶと、 使用するデフォルト値をまず指定する。

もちろん、オプションの実際の値がこの選択肢に合えば、 defaultではなく実際の値が表示される。

選択肢の値としてnilが不正であるときには、 :valueで正当なデフォルトを指定することが本質的である。

:format format-string
この文字列は、型に対応する値を表現するためにバッファに挿入される。 format-stringには、以下に示す%を使える。
%[button%]
ボタンとして印を付けたテキストbuttonを表示する。 :action属性は、ユーザーがボタンを起動したらなにを行うかを指定する。 その値は2つの引数、つまり、ボタンが現れるウィジェットとイベント を取る関数であること。

異なるアクションを有する異なるボタンを指定する方法はない。

%{sample%}
:sample-faceで指定した特別なフェイスでsampleを表示する。
%v
項目の値で置き換える。 値の表示方法は項目の種類と、 (変数の)カスタマイズ型に依存する。
%d
項目の説明文字列で置き換える。
%h
%dと同様だが、説明文字列が1行を超えるときには、 説明文字列全体を表示するか先頭行だけを表示するかを 制御するアクティブフィールドを追加する。
%t
タグで置き換える。 タグは:tagキーワードで指定する。
%%
%をそのまま表示する。

:action action
ユーザーがボタンをクリックしたらactionを行う。
:button-face face
%[...%]で表示するボタンテキストに フェイスface(フェイス名かフェイス名のリスト)を使う。
:button-prefix prefix
:button-suffix suffix
これらは、以下のようにボタンの前後に表示するテキストを指定する。
nil
テキストを挿入しない。
文字列
文字列をそのまま挿入する。
シンボル
シンボルの値を使う。

:tag tag
この型に対応する値(やその一部)に対するタグとして tag(文字列)を使う
:doc doc
この型に対応する値(やその一部)に対する説明文字列として docを使う。 これが動作するためには、 :formatの値を指定し、かつ、 その値の中で%d%hを使う必要がある。

型に対して説明文字列を指定するのは、 :choiceの選択肢や他の複合型の一部の意味について より多くの情報をユーザーに与えるためである。

:help-echo motion-doc
widget-forwardwidget-backwardでこの項目に移動すると、 エコー領域に文字列motion-docを表示する。
:match function
値がこの型に一致することを調べる方法を指定する。 対応する値functionは、2つの引数、つまり、 ウィジェットと値を取る関数であること。 受理できる値の場合にはnil以外を返すこと。


Node:Loading, Next:, Previous:Customization, Up:Top

ロード

Lispコードのファイルをロードするとは、 その内容をLispオブジェクトの形でLisp環境に取り込むことです。 Emacsは、ファイルを探してオープンし、テキストを読み取り、 各フォームを評価し、そしてファイルをクローズします。

ロード関数は、関数eval-current-bufferがバッファ内の すべての式を評価するように、ファイル内のすべての式を評価します。 異なる点は、ロード関数は、Emacsバッファ内のテキストではなく ディスク上のファイル内のテキストを読み取って評価することです。

ロードするファイルには、Lisp式のソースコードかバイトコンパイル済みコードが 入っている必要があります。 ファイルの各フォームをトップレベルのフォーム(top-level form)と 呼びます。 ロード可能なファイル内のフォーム向けの特別な書式はありません。 ファイル内のどんなフォームでも、バッファに直接打ち込んで評価できます。 (もちろん、ほとんどのコードはこのようにして試したはず。) ほとんどの場合、フォームは関数定義や変数定義です。

Lispコードを収めたファイルをしばしばライブラリ(library)と呼びます。 したがって、『rmailライブラリ』は、rmailモード用のコードを収めたファイルです。 同様に、『Lispライブラリディレクトリ』は、 Lispコードを収めたファイルのディレクトリです。


Node:How Programs Do Loading, Next:, Up:Loading

プログラムからのロード方法

Emacs Lispには、ロードのためのインターフェイスがいくつかあります。 たとえば、autoloadは、 ファイルで定義された関数向けに場所を確保するオブジェクトを作成します。 自動ロードする関数を呼び出すと、 ファイルの実際の定義を得るためにファイルをロードします(see Autoload)。 requireは、ファイルをすでにロードしていなければロードします (see Named Features)。 これらの機構はすべて、最終的には、関数loadを呼び出して動作します。

load filename &optional missing-ok nomessage nosuffix must-suffix Function
この関数は、Lispコードのファイルを探してオープンし、 その中のフォームすべてを評価してから、ファイルをクローズする。

ファイルを探すために、 loadはまずfilename.elcという名前のファイル、 つまり、filename.elcを付加した名前のファイルを探す。 そのようなファイルが存在すれば、それをロードする。 そのような名前のファイルがなければ、 loadfilename.elという名前のファイルを探す。 そのファイルが存在すれば、それをロードする。 いずれの名前のファイルもみつからなければ、 最終的に、loadは、なにも付加しないfilenameという名前のファイルを 探し、存在すればそれをロードする。 (関数loadfilenameを探す手順は賢くない。 (load "foo.el")を評価すると、 foo.el.elという名前のファイルを探してしまう。)

省略可能な引数nosuffixnil以外であれば、 .elc.elの接尾辞を試さない。 この場合、目的のファイルの正確な名前を指定する必要がある。 正確なファイル名を指定し、かつ、nosuffixtを使えば、 foo.el.elのようなファイル名を探してしまうことを防げる。

省略可能な引数must-suffixnil以外であれば、 loadは、ディレクトリ名を明示していない限り、 ファイル名は.el.elcで終るものと仮定する。 filenameにディレクトリ名が明示してなく、かつ、 接尾辞も指定してなければ、loadは接尾辞を必ず付加する。

filenamefoobaz/foo.barのように 相対ファイル名であると、loadは変数load-pathを使って ファイルを探す。 filenameload-pathに指定した各ディレクトリを付加し、 最初にみつかったファイルをロードする。 デフォルトディレクトリを表すnilload-pathに 指定されている場合に限り、カレントディレクトリを試す。 loadは、まず最初のディレクトリで3つの可能な接尾辞を試し、 続いて2番目のディレクトリで3つの可能な接尾辞を試し、 というように行う。 see Library Search

foo.elcfoo.elより古いという旨の警告を受け取った場合には、 foo.elの再コンパイルを考えるべきである。 see Byte Compilation

(コンパイルしていない)ソースファイルをロードするときには、 Emacsがファイルを訪問する場合と同様に、 loadは文字集合を変換する。 see Coding Systems

nomessagenilであると、 ロード中にはエコー領域に Loading foo...Loading foo...doneのメッセージを表示する。

ファイルをロード中に処理できないエラーに出会うと、ロードを終了する。 autoloadによるロードの場合には、 ロード中に行われた関数定義はすべてもとに戻す。

loadがロードすべきファイルをみつけられないと、 普通、(Cannot open load file filenameを伴った) エラーfile-errorを通知する。 missing-oknil以外であれば、 loadnilを返すだけである。

変数load-read-functionを使って、 式を読み取るためにreadのかわりにloadが使う関数を指定できる。 下記参照。

ファイルを正しくロードできるとloadtを返す。

load-file filename コマンド
このコマンドはファイルfilenameをロードする。 filenameが相対ファイル名であると、 現在のデフォルトディレクトリを仮定する。 load-pathを使わず、接尾辞も付加しない。 ロードするファイル名を正確に指定したい場合にこのコマンドを使う。

load-library library コマンド
このコマンドは、libraryという名前のライブラリをロードする。 loadと等価であるが、引数を対話的に読み取る点が異なる。

load-in-progress Variable
Emacsがファイルをロード処理中であると、 この変数はnil以外であり、さもなければnilである。

load-read-function Variable
この変数は、loadeval-regionが、 readのかわりに使う、式を読み取る関数を指定する。 その関数はreadと同様に引数を1つとること。

通常、この変数の値はnilであり、 これらの関数がreadを使うことを意味する。

注意: この変数を使うかわりに、eval-regionの引数read-functionとして 関数を渡す新しい別の機能を使ったほうが見通しがよい。 see Eval

Emacs構築時のloadの使い方についての情報は、 See Building Emacs


Node:Library Search, Next:, Previous:How Programs Do Loading, Up:Loading

ライブラリの探索

EmacsがLispライブラリをロードするときには、 変数load-pathで指定したディレクトリ群でライブラリを探します。

load-path User Option
この変数の値は、loadでファイルをロードするときに探索する ディレクトリのリストである。 各要素は、(ディレクトリ名である)文字列か (カレント作業ディレクトリを表す)nilである。

load-pathの値は、環境変数EMACSLOADPATHがあれば、 それで初期化します。 さもなければ、デフォルト値は、 Emacsを構築したときにemacs/src/paths.hで指定したものです。 そして、リスト内のディレクトリのサブディレクトリをリストに追加して 拡張します。

EMACSLOADPATHの構文はPATHと同じです。 :(オペレーティングシステムによっては;)で ディレクトリ名を区切ります。 デフォルトのカレントディレクトリには.を使います。 csh.loginファイルで環境変数EMACSLOADPATHを 指定する例はつぎのとおりです。

setenv EMACSLOADPATH .:/user/bil/emacs:/usr/local/share/emacs/20.3/lisp

shを使っている場合はつぎのようにします。

export EMACSLOADPATH
EMACSLOADPATH=.:/user/bil/emacs:/usr/local/share/emacs/20.3/lisp

.emacsファイルで、 デフォルトのload-pathの先頭に複数のディレクトリを追加するには、 つぎのようなコードを書きます。

(setq load-path
      (append (list nil "/user/bil/emacs"
                    "/usr/local/lisplib"
                    "~/emacs")
              load-path))

この例では、Lispコードを、まずカレント作業ディレクトリで探索し、 続いて、/user/bil/emacsディレクトリ、 /usr/local/lisplibディレクトリ、~/emacsディレクトリ、 さらに、標準のディレクトリで探索します。

Emacsのダンプには、load-pathの特別な値を使います。 ダンプ終了時にload-pathの値が未変更(つまり、同じ特別な値)であれば、 ダンプ版Emacsは起動時に、上に述べたように、普通のload-pathの値を 使います。 しかし、ダンプ終了時にload-pathの値が別の値であれば、 ダンプ版Emacsの実行でもその(別の)値を使います。

したがって、site-init.elsite-load.elで 少数のライブラリをロードするために 一時的にload-pathを変更したい場合には、 loadの呼び出しをletで囲んで load-pathをローカルに束縛するべきです。

システムにインストールしたEmacsを実行中は、 load-pathのデフォルト値には、2つの特別なディレクトリ (とそれらのサブディレクトリ)が含まれます。

"/usr/local/share/emacs/version/site-lisp"

"/usr/local/share/emacs/site-lisp"

です。 前者は、Emacsの特定の版向けにローカルにインストールしたパッケージ用です。 後者は、Emacsの任意の版向けにローカルにインストールしたパッケージ用です。

Emacsのある版向けのパッケージが別の版ではトラブルを引き起こす理由は いくつかあります。 Emacsの互換性のない変更のために更新を必要とするパッケージもあります。 予告なしに変更される可能性のある明文化していない Emacsの内部データに依存するものもあります。 Emacsの新しい版では、パッケージの特定の版と一体になっているものもあり、 その版だけで使うべきです。

Emacsは、起動すると、ディレクトリのサブディレクトリを捜し出して、 それらをload-pathに追加します。 直下のサブディレクトリも複数レベル下のサブディレクトリも load-pathに追加します。

しかし、サブディレクトリすべてを含むわけではありません。 英数字で始まらない名前のサブディレクトリは除外します。 RCSという名前のサブディレクトリも除外します。 また、.nosearchという名前のファイルを置いた サブディレクトリも除外します。 これらの方法を用いれば、site-lispディレクトリ下の 特定のサブディレクトリの探索を防げます。

Emacsを構築したディレクトリでEmacsを起動すると、 つまり、正式にインストールしてない実行形式を起動すると、 load-pathには、普通、2つのディレクトリを追加します。 主構築ディレクトリのサブディレクトリ、lispsite-lispです。 (どちらも、絶対ファイル名で表される。)

locate-library library &optional nosuffix path interactive-call コマンド
このコマンドは、ライブラリlibraryの正確なファイル名を探す。 loadと同様にライブラリを探索する。 引数nosuffixの意味はloadと同じであり、 指定した名前libraryに接尾辞.elc.elを付加しない。

pathnil以外であると、 それはload-pathのかわりに使うディレクトリのリストである。

locate-libraryをプログラムから呼び出した場合、 文字列でファイル名を返す。 ユーザーがlocate-libraryを対話的に実行した場合、 引数interactive-calltであり、これは locate-libraryに対してファイル名をエコー領域に表示するように指示する。


Node:Loading Non-ASCII, Next:, Previous:Library Search, Up:Loading

非ASCII文字のロード

Emacs Lispプログラムが非ASCII文字の文字列定数を含む場合、 Emacs内部では、それらはユニバイト文字列かマルチバイト文字列で表現できます (see Text Representations)。 どちらの表現形式を用いるかは、 どのようにファイルをEmacsに読み込んだかに依存します。 マルチバイト表現へ復号化して読んだ場合には、 Lispプログラムのテキストはマルチバイトテキストになり、 その文字列定数はマルチバイト文字列になります。 (たとえば)Lantin-1文字を含むファイルを復号化せずに読むと、 プログラムテキストはユニバイトテキストになり、 その文字列定数はユニバイト文字列になります。 See Coding Systems

結果をより予測可能にするために、 オプション--unibyteを指定して起動した場合であっても、 Lispファイルをロードするときには、 Emacsはつねにマルチバイト表現に復号化します。 つまり、非ASCII文字の文字列定数はマルチバイト文字列に変換します。 唯一の例外は、特定のファイルで無変換を指定した場合だけです。

Emacsをこのように設計したのは、 Emacsの起動方法によらずに、 Lispプログラムが予測可能な結果をもたらすようにするためです。 さらに、こうすることで、ユニバイト動作のEmacsであっても、 マルチバイトテキストを使うことに依存したプログラムが動作します。 もちろん、そのようなプログラムは、 default-enable-multibyte-charactersを検査して適切に表現を変換して、 ユーザーがユニバイトテキストとマルチバイトテキストのどちらを 好んでいるか調べるように設計すべきです。

Emacs Lispのほとんどのプログラムでは、 非ASCII文字列はマルチバイト文字列であるということに 気づかないでしょう。 というのは、それらをユニバイトバッファに挿入すると 自動的にユニバイトに変換するからです。 しかしながら、これで違いがでるならば、 Lispファイルの先頭行のコメントに-*-unibyte: t;-*-と書くことで、 特定のLispファイルをユニバイトと解釈するように強制できます。 このように指定すると、マルチバイト動作のEmacsであっても、 そのファイルを無条件にユニバイトと解釈します。


Node:Autoload, Next:, Previous:Loading Non-ASCII, Up:Loading

自動ロード

自動ロード(autoload)機能により、 関数やマクロを定義しているファイルをロードしていなくても、 関数やマクロをLispに登録できます。 関数を初めて呼び出すと、 適切なファイルを読み込んで実際の定義と関連する他のコードを インストールしてから、すでにロードしてあったかのように実際の定義を実行します。

関数を自動的にロードするように設定する方法は2つあります。 autoloadを呼び出すか、あるいは、 ソース内の実際の定義のまえに特別な『マジック』コメントを書きます。 autoloadは自動ロードを行う低レベルの基本関数です。 任意のLispプログラムでいつでもautoloadを呼び出せます。 マジックコメントは、Emacsで使うパッケージ向けに 関数を自動的にロードするように設定するとても便利な方法です。 これらのコメントそのものはなにもしませんが、 コマンドupdate-file-autoloadsに対する指針として働きます。 このコマンドは、autoloadの呼び出しを作成し、 Emacs構築時にそれらを実行するように設定します。

autoload function filename &optional docstring interactive type Function
この関数は、functionという名前の関数(やマクロ)を filenameから自動的にロードするように定義する。 文字列filenameは、functionの実際の定義を取得するために ロードするファイルを指定する。

filenameにディレクトリ名や接尾辞.el.elcがなければ、 autoloadはこれらの接尾辞の1つを必ず付加し、 接尾辞を付けないfilenameという名前のファイルはロードしない。

引数docstringは、関数に対する説明文字列である。 通常、これは関数定義そのものの説明文字列と同一であること。 autoloadの呼び出しにおいて説明文字列を指定しておくことで、 関数の実際の定義をロードしなくても説明文を見ることが可能になる。

interactivenil以外ならば、 functionを対話的に呼び出せることを意味する。 つまり、関数の実際の定義をロードしなくても M-xの補完が動作するのである。 完全な対話指定を指定しない。 ユーザーがfunctionを実際に呼び出すまでは必要なく、 呼び出し時点で実際の定義をロードするからである。

普通の関数と同様に、マクロやキーマップも自動的にロードできる。 functionが実際にはマクロならば、typeにはmacroを指定する。 functionが実際にはキーマップならば、 typeにはkeymapを指定する。 Emacsのさまざまな部分では、 実際の定義をロードせずにこの情報を知る必要がある。

自動ロードと指定したキーマップは、 プレフィックスキーのバインディングがシンボルfunctionであるときに、 キーを探す過程で自動的にロードする。 キーマップのこれ以外の参照方法では、自動的にロードしない。 特に、変数名がシンボルfunctionと同じであっても、 Lispプログラムで変数の値からキーマップを取得して define-keyを呼び出す場合には、自動的にロードしない。

functionが自動ロードオブジェクトではない 空でない関数定義を有する場合には、 autoloadはなにもせずにnilを返す。 functionの関数セルが空であったり、 すでに自動ロードオブジェクトである場合には、 つぎのような自動ロードオブジェクトとして関数セルを定義する。

(autoload filename docstring interactive type)

たとえばつぎのとおり。

(symbol-function 'run-prolog)
     => (autoload "prolog" 169681 t nil)

この場合、"prolog"はロードすべきファイルの名前であり、 169681はファイルemacs/etc/DOC-version (see Documentation Basics)内の説明文字列を指す。 tは関数が対話的であることを示し、 nilはマクロでもキーマップでもないことを示す。

自動ロード対象のファイルでは、通常、他の定義や 複数の機能を提供したり必要としたりします。 (その内容の評価中のエラーなどで)ファイルを完全にロードできないと、 ロード中に行った関数定義やprovideの呼び出しをもとに戻します。 そのファイルから自動ロードする任意の関数をつぎに呼び出そうとしたときに、 そのファイルを再度ロードすることを保証するためです。 こうしておかないと、 自動ロードをアボートしたファイルで関数が定義されても、 そのファイルのうしろの部分で定義される その関数に必要なサブルーティンが必ずしもロードされないために その関数が動作しない可能性があるからです。

自動ロード対象のファイルで必要なLisp関数やマクロの定義に失敗すると、 "Autoloading failed to define function function-name"を 伴ったエラーを通知します。

自動ロードを指定するマジックコメントは、 ;;;###autoloadだけを書いた行であり、 自動ロード対象のソースファイル上で実際の関数定義の直前に必要です。 コマンドM-x update-file-autoloadsは、 対応するautoload呼び出しをloaddefs.elに書き込みます。 Emacs構築時にはloaddefs.elをロードするので、 autoloadを呼び出します。 M-x update-directory-autoloadsはもっと強力で、 カレントディレクトリのすべてのファイルに対する自動ロード情報を更新します。

同じマジックコメントは、任意の種類のフォームをloaddefs.elに コピーできます。 マジックコメントに続くフォームが関数定義でない場合、 そのフォームをそのままコピーします。 構築時にはフォームを実行しても、 ファイルのロード時にはそのフォームを実行しないように マジックコメントを使うこともできます。 そうするには、マジックコメントと同じ行にそのフォームを書きます。 するとそれはコメントなので、ソースファイルをロードするときにはなにもしません。 一方、M-x update-file-autoloadsはそのフォームをloaddefs.elに コピーするので、Emacs構築時には実行されるのです。

つぎの例は、マジックコメントを使ってdoctorを自動ロードする方法です。

;;;###autoload
(defun doctor ()
  "Switch to *doctor* buffer and start giving psychotherapy."
  (interactive)
  (switch-to-buffer "*doctor*")
  (doctor-mode))

こうすると、loaddefs.elではつぎのようになります。

(autoload 'doctor "doctor"
  "\
Switch to *doctor* buffer and start giving psychotherapy."
  t)

ダブルクォートの直後にバックスラッシュや改行を書く慣習は、 loaddefs.elなどの あらかじめロードするLispファイルの中だけで使うものです。 これは、make-docfileに対して、 説明文字列をetc/DOCファイルに書くように指示します。 See Building Emacs


Node:Repeated Loading, Next:, Previous:Autoload, Up:Loading

ロードの繰り返し

1つのEmacsセッションにおいて、あるファイルを複数回ロードできます。 たとえば、バッファ内の関数定義を編集して、 関数定義を書き直してインストールし直したあとで、 もとの版に戻したいこともあるでしょう。 これには、もとのファイルを再ロードすればよいのです。

ファイルをロードしたり再ロードするとき、 関数loadload-libraryは、 コンパイルしていないファイルではなく、 バイトコンパイル済みのファイルを自動的にロードすることに注意してください。 ファイルを書き直して保存してから再インストールする場合、 新しい版をバイトコンパイルする必要があります。 さもないと、Emacsは、新しいコンパイルしていないファイルではなく、 バイトコンパイル済みの古いファイルをロードしてしまいます。 そのような場合、ファイルをロードすると、 (compiled; note, source is newer)とメッセージを表示して、 再コンパイルするように忠告してきます。

Lispライブラリファイルにフォームを書くときには、 ファイルを複数回ロードする可能性があることを忘れないでください。 たとえば、ライブラリを再ロードするたびに 各変数を再初期化すべきかどうか考えましょう。 defvarは、初期化済みの変数の値を変更しません。 (see Defining Variables。)

連想リストに要素を追加するもっとも簡単な方法はつぎのとおりです。

(setq minor-mode-alist
      (cons '(leif-mode " Leif") minor-mode-alist))

しかし、これでは、ライブラリを再ロードすると、 複数の要素を追加してしまいます。 これを避けるにはつぎのようにします。

(or (assq 'leif-mode minor-mode-alist)
    (setq minor-mode-alist
          (cons '(leif-mode " Leif") minor-mode-alist)))

リストに要素を1回だけ追加するには、 add-to-list(see Setting Variables)も使えます。

ライブラリをすでにロードしたかどうか明示的に調べたいこともあるでしょう。 ライブラリ内で以前ロードされたかどうか検査する方法の1つは、 つぎのとおりです。

(defvar foo-was-loaded nil)

(unless foo-was-loaded
  execute-first-time-only
  (setq foo-was-loaded t))

ライブラリで名前付き機能を提供するためにprovideを使っていれば、 ファイルの始めのほうでfeaturepを使って、 provideを以前呼び出したかどうか検査できます。


Node:Named Features, Next:, Previous:Repeated Loading, Up:Loading

機能

providerequireは、 ファイルを自動的にロードするためのautoloadの代替手段です。 それらは指定した機能(features)という考え方で動作します。 自動ロードは特定の関数を呼び出すことで起動しますが、 機能はその名前でプログラムが最初に要求したときにロードします。

機能名は、関数や変数などの集合を表すシンボルです。 それらを定義するファイルでは、その機能を提供(provide)します。 それらを使う別のプログラムでは、 その機能を要求(require)することで、 それらが定義されることを確実にします。 こうすると、未ロードであれば定義しているファイルをロードします。

機能を要求するには、機能名を引数にしてrequireを呼び出します。 requireは、グローバル変数featuresを調べて、 目的の機能がすでに提供されているかどうか調べます。 提供されていなければ、適当なファイルから機能をロードします。 このファイルでは、トップレベルでprovideを呼び出して、 featuresに機能を追加するべきです。 そうしないと、requireはエラーを通知します。

たとえば、emacs/lisp/prolog.el には、 つぎのコードのようなrun-prologの定義が入っています。

(defun run-prolog ()
  "Run an inferior Prolog process, with I/O via buffer *prolog*."
  (interactive)
  (require 'comint)
  (switch-to-buffer (make-comint "prolog" prolog-program-name))
  (inferior-prolog-mode))

(require 'comint)は、ファイルcomint.elが未ロードであると、 そのファイルをロードします。 これにより、make-comintが定義済みであることを保証します。 普通、機能には、その機能を提供するファイル名からとった名前を付けますから、 requireにファイル名を指定する必要はありません。

comint.elファイルには、つぎのトップレベルの式が入っています。

(provide 'comint)

これにより、グローバル変数featuresのリストに comintが追加されるので、 これ以降に(require 'comint)を実行しても、 なにもしないでよいことになります。

ファイルのトップレベルでrequireを使うと、 そのファイルをロードする場合と同様に、 そのファイルをバイトコンパイルするとき(see Byte Compilation)にも requireには効果があります。 要求したパッケージに、 バイトコンパイラが知っている必要があるマクロが入っている場合です。

トップレベルのrequireの呼び出しは、 バイトコンパイル中に評価されますが、 provideの呼び出しは評価しません。 したがって、つぎの例のように、 同じ機能に対するprovideに続けてrequireを書くことで、 バイトコンパイルするまえに定義のファイルをロードすることを確実にできます。

(provide 'my-feature)  ; バイトコンパイラは無視し、
                       ;   loadは評価する
(require 'my-feature)  ; バイトコンパイラは評価する

コンパイラはprovideを無視し、 続くrequireの処理では当該ファイルをロードします。 ファイルのロード時にはprovideの呼び出しを実行するので、 そのあとのrequireの呼び出しは、 ファイルをロードするときにはなにもしません。

provide feature Function
この関数は、機能featureをロードし終えたこと、あるいは、 ロード中であることを現在のEmacsセッション内で宣言する。 つまり、featureに関連した機能が他のLispプログラムから利用できることを 意味する。

provideの呼び出しの直接の効果は、 featureがリストfeaturesに入っていなければ、 featureをリストfeaturesの先頭に入れることである。 引数featureはシンボルであること。 providefeatureを返す。

features
     => (bar bish)

(provide 'foo)
     => foo
features
     => (foo bar bish)

自動ロードによってファイルをロードしているとき、 その内容を評価することでエラーになってロードを中止すると、 ロード中に行われた関数定義やprovideの呼び出しはもとに戻す。 see Autoload

require feature &optional filename Function
この関数は((featurep feature)を使って) 現在のEmacsセッション内にfeatureが存在するかどうか調べる。 引数featureはシンボルであること。

機能が存在していなければ、requireは、 loadを使ってfilenameをロードする。 filenameを指定しないと、シンボルfeatureの名前を ロードすべきファイル名の基にする。 しかしながら、この場合には、requireは、 接尾辞を必ず付加してfeatureを探す。 featureだけの名前のファイルは探さない。

featureを提供するファイルのロードに失敗すると、 requireはエラー Required feature feature was not providedを通知する。

featurep feature Function
この関数は、現在のEmacsセッションでfeatureが提供されていれば (つまり、featurefeaturesのメンバであれば) tを返す。

features Variable
この変数の値は、 現在のEmacsセッションにロード済みの機能を表すシンボルのリストである。 各シンボルは、provideを呼び出すことでこのリストに追加される。 リストfeatures内の要素の順番は関係ない。


Node:Unloading, Next:, Previous:Named Features, Up:Loading

アンロード

ライブラリでロードした関数や変数を捨てさって 他のLispオブジェクト向けにメモリを回収することができます。 そうするには関数unload-featureを使います。

unload-feature feature &optional force コマンド
このコマンドは、featureを提供するライブラリをアンロードする。 つまり、当該ライブラリにおいて、defundefaliasdefsubstdefmacrodefconstdefvardefcustomで定義した関数、マクロ、変数すべてを未定義にする。 そうして、これらのシンボルに以前設定してあった自動ロードの設定を復元する。 (ロード時に、これらをシンボルの属性autoloadに保存している。)

以前の定義に復元するまえに、unload-featureremove-hookを 実行して、ライブラリ内の関数を特定のフックから取り除く。 これらのフックは、-hook-hooksで終る名前の変数、および、 loadhist-special-hooksに入っているものである。 これは、重要なフックにおいて存在しない関数を参照することで Emacsが動作不能になるのを防ぐ。

これらの処置でも誤動作防止には不十分であるときには、 ライブラリで明示的なアンロードフックを定義できる。 feature-unload-hookを定義してあると、 以前の定義を復元するまえに、 フックを削除する通常の動作のかわりに このフックをノーマルフックとして実行する。 アンロードフックでは、 ライブラリをいったんアンロードすると動作不能になるような ライブラリで変更したグローバルな状態をすべてアンドゥすべきである。

通常、unload-featureは、他のライブラリが依存している ライブラリのアンロードは拒否する。 (ライブラリabrequire(要求)していると、 ライブラリaはライブラリbに依存している。) 省略可能な引数forcenil以外であると、 依存関係を無視し、任意のライブラリをアンロードできる。

関数unload-featureはLispで書いてあり、 その動作はload-historyに基づきます。

load-history Variable
この変数の値は、ライブラリ名をそのライブラリが定義する関数や変数の名前、 そのライブラリが提供する機能、そのライブラリが要求する機能に対応付ける 連想リストである。

各要素はリストであり、1つ1つが1つのライブラリを記述する。 リストのCARは文字列であり、ライブラリ名である。 リストの残りは、以下の種類のオブジェクトから成る。

  • このライブラリで定義されたシンボル。
  • (require . feature)の形のリストであり、 要求する機能を示す。
  • (provide . feature)の形のリストであり、 提供する機能を示す。

load-historyの値には、CARnilであるような 1つの要素があってもよい。 この要素は、ファイルを訪問してないバッファ内でeval-bufferによって 作られた定義であることを示す。

コマンドeval-regionload-historyを更新しますが、 訪問先ファイルに対応する要素に、定義されるシンボルを追加するのであって、 要素を置き換えるのではありません。

あらかじめロード済みのライブラリは、load-historyに寄与しません。

loadhist-special-hooks Variable
この変数は、ライブラリ内で定義された関数を削除するために ライブラリをアンロードするまえに走査するフックのリストを保持する。


Node:Hooks for Loading, Previous:Unloading, Up:Loading

ロード時のフック

eval-after-loadを呼び出すと、 特定のライブラリをロードする/してあるときに実行するコードを指定できます。

eval-after-load library form Function
この関数は、ライブラリlibraryをロードする/してあるときに、 ライブラリlibraryのロードの最後にformを評価するように設定する。 libraryをすでにロードしてあると、 この関数はformをただちに評価する。

ライブラリ名libraryloadの引数に正確に一致する必要がある。 load-pathを探索してインストールするライブラリを探したときに 正しい結果を得るために、libraryにはディレクトリ名を含めないこと。

formでエラーが発生してもロード処理をもとに戻さないが、 formの残りは実行しない。

一般に、よく設計されたLispプログラムはこの機能を使うべきではありません。 Lispライブラリを見通しよくモジュール化して扱うには、 (1)ライブラリの(外部から使うことを意図した)変数を調べて設定し、 (2)ライブラリの関数を呼び出すことです。 (1)を行いたければ、すぐにしてかまいません。 ライブラリをロードするまで待つ必要はありません。 (2)を行うには、ライブラリをロードする必要があります (requireで行うことが好ましい)。

広く使われるプログラムに対する設計基準に合わなくても、 個人のカスタマイズでeval-after-loadを使うのはかまいません。

after-load-alist Variable
特定のライブラリをロードする/してあるときに評価する式の連想リスト。 各要素はつぎのとおり。
(filename forms...)

関数loadは、eval-after-loadを実現するために after-load-alistを調べる。


Node:Byte Compilation, Next:, Previous:Loading, Up:Top

バイトコンパイル

Emacs Lispには、Lispで書いた関数を より効率よく実行可能なバイトコード(byte-code)と呼ばれる 特別な表現に変換するコンパイラ(compiler)があります。 コンパイラはLispの関数定義をバイトコードで置き換えます。 バイトコード関数を呼び出すと、 バイトコードインタープリタ(byte-code interpreter)が その定義を評価します。

(真のコンパイル済みコードのように)計算機ハードウェアが直接実行するかわりに、 バイトコードインタープリタがバイトコンパイル済みのコードを評価するので、 バイトコードは、再コンパイルせずに計算機から計算機に移せます。 しかしながら、真のコンパイル済みコードほど速くはありません。

EmacsバイトコンパイラがLispファイルをコンパイルするときには、 --unibyteを指定してEmacsを起動したとしても、 ファイルで特に指定しなければ、 つねにファイルをマルチバイトテキストとして読みます。 コンパイルしても、コンパイルせずに同じファイルを実行した場合と同じ結果を 得るようにするためです。 See Loading Non-ASCII

一般に、Emacsの任意の版は、それよりまえの版でバイトコンパイルしたコードを 実行できますが、その逆は真ではありません。 Emacs 19.29では互換性のない大きな変更を行いましたから、 それ以降の版でコンパイルしたファイルは、 特別なオプションを指定しない限り、それ以前の版ではまったく動きません。 さらに、Emacs 19.29では、キーボード文字の修飾ビットを変更しました。 その結果、19.29よりまえの版でコンパイルしたファイルは、 修飾ビットを含む文字定数を使っているとそれ以降の版では動作しません。

バイトコンパイル中に生起するエラーについては、 See Compilation Errors


Node:Speed of Byte-Code, Next:, Up:Byte Compilation

バイトコンパイルコードの性能

バイトコンパイルした関数は、Cで書いた基本関数ほど効率よくはありませんが、 Lispで書いた版よりはよほど速く動きます。 例を示しましょう。

(defun silly-loop (n)
  "Return time before and after N iterations of a loop."
  (let ((t1 (current-time-string)))
    (while (> (setq n (1- n))
              0))
    (list t1 (current-time-string))))
=> silly-loop

(silly-loop 100000)
=> ("Fri Mar 18 17:25:57 1994"
    "Fri Mar 18 17:26:28 1994")  ; 31秒

(byte-compile 'silly-loop)
=> [コンパイルしたコードは省略]

(silly-loop 100000)
=> ("Fri Mar 18 17:26:52 1994"
    "Fri Mar 18 17:26:58 1994")  ; 6秒

この例では、解釈実行するコードでは実行に31秒必要でしたが、 バイトコンパイルしたコードでは6秒でした。 この結果は代表的なのもですが、実際の結果は大きく変動します。


Node:Compilation Functions, Next:, Previous:Speed of Byte-Code, Up:Byte Compilation

コンパイル関数

関数byte-compileで、 個々の関数定義やマクロ定義をバイトコンパイルできます。 byte-compile-fileで1つのファイル全体をコンパイルしたり、 byte-recompile-directorybatch-byte-compileで 複数個のファイルをコンパイルできます。

バイトコンパイラは、 各ファイルに対するエラーメッセージや警告メッセージを *Compile-Log*と呼ばれるバッファに出力します。 読者のプログラムに関してここに報告されたことがらは、 問題点を指摘しますが、必ずしもエラーとは限りません。

バイトコンパイルする可能性のあるファイルにマクロ呼び出しを書くときには 注意してください。 マクロ呼び出しはコンパイル時に展開されるので、 正しくコンパイルするためにはマクロは定義済みである必要があります。 詳しくは、See Compiling Macros

通常、ファイルをコンパイルしてもファイルの内容を評価したり、 ファイルをロードしません。 しかし、ファイルのトップレベルに書いたrequireは実行します。 コンパイル時に必要なマクロ定義が存在することを保証する1つの方法は、 それらを定義するファイルを要求(require)することです (see Named Features)。 コンパイルしたプログラムを実行するときに マクロ定義ファイルのロードを防ぐには、 requireの呼び出しの周りにeval-when-compileを書きます (see Eval During Compile)。

byte-compile symbol Function
この関数は、symbolの関数定義をバイトコンパイルし、 以前の定義をコンパイルしたもので置き換える。 symbolの関数定義は、関数の実際のコードであること。 つまり、コンパイラは、別のシンボルへの間接参照を辿らない。 byte-compileは、symbolのコンパイル済みの新たな定義を返す。

symbolの定義がバイトコード関数オブジェクトであると、 byte-compileはなにもせずにnilを返す。 Lispはどんなシンボルに対しても関数定義を1つだけ記録するので、 それがすでにコンパイル済みであると、 コンパイルまえのコードはどこにもないのである。 したがって、『同じ定義をコンパイルし直す』方法はない。

(defun factorial (integer)
  "Compute factorial of INTEGER."
  (if (= 1 integer) 1
    (* integer (factorial (1- integer)))))
=> factorial

(byte-compile 'factorial)
=>
#[(integer)
  "^H\301U\203^H^@\301\207\302^H\303^HS!\"\207"
  [integer 1 * factorial]
  4 "Compute factorial of INTEGER."]

結果は、バイトコード関数オブジェクトである。 この文字列には実際のバイトコードが入っている。 その各文字は、命令や命令のオペランドである。 ベクトルには、特別な命令に符号化される特定の基本関数を除いて、 関数が使うすべての定数、変数名、関数名が入っている。

compile-defun コマンド
このコマンドはポイントを含むdefunを読み取り、 それをコンパイルして、結果を評価する。 実際に関数定義であるdefunでこのコマンドを使うと、 その関数をコンパイルしたものをインストールすることになる。

byte-compile-file filename コマンド
この関数は、filenameという名前のLispコードのファイルを コンパイルしバイトコードのファイルにする。 出力ファイルの名前は、接頭辞.el.elcに換えて作る。 filename.elで終っていないときには、 filenameの末尾に.elcを付加する。

入力ファイルから一度に1つずつフォームを読みながらコンパイルを行う。 それが関数定義やマクロ定義であると、 コンパイルした関数定義やマクロ定義を書き出す。 他のフォームは一塊にして、各塊をコンパイルして書き出し、 ファイルを読むとコンパイルしたコードが実行されるようにする。 入力ファイルを読むときにすべてのコメントを捨てる。

このコマンドはtを返す。 対話的に呼び出すとファイル名を問い合わせる。

% ls -l push*
-rw-r--r--  1 lewis     791 Oct  5 20:31 push.el

(byte-compile-file "~/emacs/push.el")
     => t

% ls -l push*
-rw-r--r--  1 lewis     791 Oct  5 20:31 push.el
-rw-rw-rw-  1 lewis     638 Oct  8 20:25 push.elc

byte-recompile-directory directory flag コマンド
この関数は、directoryにある再コンパイルが必要な 個々の.elファイルを再コンパイルする。 ファイルを再コンパイルする必要があるのは、 .elcファイルが存在しても.elファイルより古い場合である。

.elファイルに対応する.elcファイルが存在しない場合には、 flagが動作を指示する。 それがnilであると、そのようなファイルは無視する。 nil以外であると、そのような各ファイルをコンパイルするかどうか ユーザーに問い合わせる。

このコマンドの戻り値は予測できない。

batch-byte-compile Function
この関数は、コマンド行に指定したファイル群に対して byte-compile-fileを実行する。 この関数はEmacsをバッチモードで実行しているときにだけ使うこと。 完了するとEmacsを終了するからである。 1つのファイルでエラーが発生しても、後続のファイルの処理には影響しないが、 エラーを起こしたファイルに対する出力ファイルは生成せず、 Emacsのプロセスは0以外の状態コードで終了する。
% emacs -batch -f batch-byte-compile *.el

byte-code code-string data-vector max-stack Function
この関数はバイトコードを実際に解釈実行する。 バイトコンパイルした関数は、実際には、 byte-codeを呼び出すような本体として定義される。 この関数を読者自身で呼び出さないこと。 この関数の正しい呼び出しを生成する方法はバイトコンパイラだけが知っている。

Emacs 18版では、バイトコードは関数byte-codeをつねに呼び出すことで 実行していた。 現在では、バイトコード関数オブジェクトの一部としてバイトコードを実行するのが 普通であり、byte-codeを明示的に呼び出すことは稀である。


Node:Docs and Compilation, Next:, Previous:Compilation Functions, Up:Byte Compilation

説明文字列とコンパイル

バイトコンパイルしたファイルからロードした関数や変数では、 それらの説明文字列は、必要に応じてそのファイルを動的に参照します。 これはEmacs内のメモリを節約しロード処理も速くなります。 というのは、ファイルのロード処理で説明文字列を処理する必要がないからです。 説明文字列を実際に参照するのは遅くなりますが、 普通、ユーザーをいらいらさせるほとではありません。

説明文字列を動的に参照することには欠点があります。

読者のサイトでEmacsを通常の手順でインストールした場合には、 これらの問題は普通起こらないはずです。 新版のインストールには別のディレクトリを使いますから、 旧版をインストールしてある限り、そのファイル群は意図した場所に 無変更で残っているはずです。

しかしながら、読者自身がEmacsを構築して、 構築したディレクトリからEmacsを使う場合、 Lispファイルを編集して再コンパイルすると、 しばしばこの問題を経験するでしょう。 そのような場合には、再コンパイルしたあとでファイルを再ロードすれば 問題を解決できます。

旧版ではこの機能を使えないので、 Emacsの(19.29以降の)最近の版でバイトコンパイルしたファイルは 旧版ではロードできません。 byte-compile-dynamic-docstringsnilを設定すれば、 コンパイル時にこの機能をオフにできます。 Emacsの旧版にロードできるようにファイルをコンパイルできるのです。 すべてのファイルをこのようにコンパイルしたり、あるいは、 この変数をファイルにローカルな束縛に指定して1つのソースファイルだけを このようにコンパイルしたりもできます。 そのようにする1つの方法は、つぎの文字列をファイルの先頭行に追加することです。

-*-byte-compile-dynamic-docstrings: nil;-*-

byte-compile-dynamic-docstrings Variable
これがnil以外であると、 バイトコンパイラは、説明文字列を動的にロードするように設定した コンパイル済みファイルを生成する。

説明文字列を動的に扱う場合、 コンパイル済みのファイルではLispリーダの特別な構文#@countを 使います。 この構文は後続のcount文字を読み飛ばします。 また、#$という構文も使います。 これは、『文字列としてのこのファイルの名前』を表します。 Lispのソースファイルでは、これらの構文を使わないのが最良です。 これらは人が読むファイル向けに設計したものではないからです。


Node:Dynamic Loading, Next:, Previous:Docs and Compilation, Up:Byte Compilation

個別関数の動的ロード

ファイルをコンパイルするとき、 動的関数ロード(dynamic function loading、 遅延ロード(lazy loading)ともいう)機能を指定できます。 動的関数ロードでは、ロードするときにファイル内の関数定義をすべて 読むわけではありません。 そのかわりに、各関数定義には、 そのファイルを指す埋め草が入っています。 それぞれの関数を初めて呼び出したときに、 その完全な定義をファイルから読み取り、埋め草を置き換えます。

動的関数ロードの利点は、ファイルをロードするよりかなり速いことです。 ユーザーが呼び出せる数多くの別々の関数を収めたファイルにおいては、 それらの1つだけを使って残りのものを使わないのであれば、 これは有利なことです。 キーボードコマンドを提供する特別なモードには、 しばしばこのような使い方のパターンがあります。 ユーザーがモードを起動しても、提供するコマンドの一部しか使わないのです。

動的関数ロードの機能には、ある種の欠点もあります。

Emacsのファイル群をインストールした普通の状況では、 このような問題は起きないはずです。 しかし、Lispファイルを読者が変更すると起こりえます。 これらの問題を回避するもっとも簡単な方法は、 再コンパイルするたびに新たにコンパイルしたファイルを ただちに再ロードすることです。

バイトコンパイラは、コンパイル時に変数byte-compile-dynamicnil以外であれば、動的関数ロードの機能を使います。 動的ロードは特定のファイルで必要なだけですから、 この変数をグローバルに設定しないでください。 そのかわりにファイルにローカルな変数束縛を使って 特定のソースファイルだけでこの機能をオンにします。 たとえば、ソースファイルの先頭行につぎのテキストを書けば、 そのようにできます。

-*-byte-compile-dynamic: t;-*-

byte-compile-dynamic Variable
これがnil以外であると、 バイトコンパイラは、動的関数ロードを使うように設定した コンパイル済みのファイルを生成する。

fetch-bytecode function Function
functionを完全にロードしていないと、 バイトコンパイルしたファイルからただちにfunctionの定義をロードする。 引数functionは、バイトコード関数オブジェクトか関数名である。


Node:Eval During Compile, Next:, Previous:Dynamic Loading, Up:Byte Compilation

コンパイル時の評価

プログラムのコンパイル時に評価されるようなコードを書くための機能です。

eval-and-compile body Special Form
このフォームは、コンパイルしたり実行したり (コンパイルしてあってもしてなくても)するときに bodyを評価するように印を付ける。

bodyを別のファイルに収め、そのファイルをrequireで参照しても 同じ結果を得ることができる。 bodyが大きい場合には、そのほうが好ましい。

eval-when-compile body Special Form
このフォームは、コンパイルしたプログラムをロードするときではなく、 プログラムのコンパイル時にbodyを評価するように印を付ける。 コンパイラが評価した結果は、コンパイルしたプログラム内に定数として現れる。 ソースファイルをコンパイルせずにロードすると、 bodyを普通どおり評価する。

Common Lispに関した注意: トップレベルでは、 Common Lispの(eval-when (compile eval) ...)の常套句に似ている。 それ以外の箇所では、Common Lispの#.リーダマクロは (解釈実行時ではなければ)eval-when-compileが行うことに近い。


Node:Byte-Code Objects, Next:, Previous:Eval During Compile, Up:Byte Compilation

バイトコード関数オブジェクト

バイトコンパイルした関数は、特別なデータ型、 バイトコード関数オブジェクト(byte-code function objects)です。

内部的には、バイトコード関数オブジェクトはベクトルによく似ています。 しかし、評価時にこのデータ型が呼び出すべき関数として現れると、 特別に扱います。 バイトコード関数オブジェクトの表示表現はベクトルに似ていますが、 開き角括弧[のまえに余分に#が付きます。

バイトコード関数オブジェクトには、少なくとも4つの要素が必要です。 最大個数に制限はありませんが、最初の6つ個の要素にだけ 普通の用途があります。 つぎのとおりです。

引数リスト
引数シンボルのリスト。
バイトコード
バイトコード命令を収めた文字列。
定数群
バイトコードが参照するLispオブジェクトのベクトル。 関数名や変数名として使われるシンボルを含む。
スタックサイズ
この関数に必要なスタックサイズの最大値。
説明文字列
(あれば)説明文字列。 さもなければnil。 説明文字列がファイルに収めてあれば、値は数かリストである。 実際の説明文字列を取得するには関数documentationを使う (see Accessing Documentation)。
対話指定
(あれば)対話指定。 これは文字列かLisp式。 対話的でない関数ではnil

バイトコード関数オブジェクトの例を表示表現でつぎに示します。

#[(&optional arg)
  "^H\204^F^@\301^P\302^H[!\207"
  [arg 1 forward-sexp]
  2
  254435
  "p"]

バイトコードオブジェクトを作る基本的な方法は、 make-byte-codeを使うことです。

make-byte-code &rest elements Function
この関数は、elementsを要素とする バイトコード関数オブジェクトを作成し返す。

バイトコード関数の要素を自分で作ったりしないでください。 それらに整合性がないと、 その関数を呼び出すとEmacsがクラッシュすることもあります。 これらのオブジェクトの作成は、バイトコンパイラに任せるべきです。 バイトコンパイラは整合した要素を作成します(と期待する)。

バイトコードオブジェクトの要素はarefで参照できます。 同じ要素群のベクトルをvconcatで作ることもできます。


Node:Disassembly, Previous:Byte-Code Objects, Up:Byte Compilation

バイトコードの逆アセンブル

人間はバイトコードを書きません。 それはバイトコンパイラの仕事です。 しかし、好奇心を満たすために逆アセンブラを用意してあります。 逆アセンブラはバイトコンパイルしたコードを人が読める形式に変換します。

バイトコードインタープリタは、単純なスタックマシンとして実装してあります。 値を自前のスタックに積み、計算に使うためにスタックから取り出し、 計算結果そのものはスタックにまた積みます。 バイトコード関数から戻るときには、スタックから値を取り出して 関数値としてその値を返します。

スタックに加えて、変数とスタックのあいだで値を転送することで、 バイトコード関数は、普通のLisp変数を使ったり、 束縛したり、値を設定できます。

disassemble object &optional stream コマンド
この関数はobjectの逆アセンブルしたコードを出力する。 streamを指定すると、そこへ出力する。 さもなければ、逆アセンブルしたコードはストリームstandard-outputへ 出力する。 引数objectは関数名かラムダ式である。

特別な例外として、この関数を対話的に使うと、 *Disassemble*という名前のバッファへ出力する。

disassemble関数の使用例を2つ示します。 バイトコードとLispソースとの対応を取れるように 特別なコメントを追加してありますが、 これらはdisassembleの出力には現れません。 これらの例は、最適化してないバイトコードです。 現在、バイトコードは、普通、最適化しますが、 目的は果たせるので、例を書き換えてありません。

(defun factorial (integer)
  "Compute factorial of an integer."
  (if (= 1 integer) 1
    (* integer (factorial (1- integer)))))
     => factorial

(factorial 4)
     => 24

(disassemble 'factorial)
     -| byte-code for factorial:
 doc: Compute factorial of an integer.
 args: (integer)

0   constant 1              ; スタックに1を積む

1   varref   integer        ; 環境からintegerの値を取得し、
                            ; スタックに積む

2   eqlsign                 ; スタックの先頭から2つの値を
                            ; 取りさって比較し、
                            ; 結果をスタックに積む

3   goto-if-nil 10          ; スタックの先頭から値を取りさり
                            ; 検査する。nilならば10へ飛び、
                            ; さもなければつぎへ進む

6   constant 1              ; スタックに1を積む

7   goto     17             ; 17へ飛ぶ(この場合、関数は1を返す)

10  constant *              ; スタックにシンボル*を積む

11  varref   integer        ; スタックにintegerの値を積む

12  constant factorial      ; スタックにfactorialを積む

13  varref   integer        ; スタックにintegerの値を積む

14  sub1                    ; スタックからintegerを取りさり、
                            ; 減した新たな値をスタックに積む

                            ; スタックの現在の内容はつぎのとおり
                            ; - integerを減らした値
                            ; - factorial
                            ; - integerの値
                            ; - *

15  call     1              ; スタックの最初(先頭)要素を使って
                            ; 関数factorialを呼び出す
                            ; 戻り値をスタックに積む

                            ; スタックの現在の内容はつぎのとおり
                            ; - factorialの
                            ;      再帰呼び出しの結果
                            ; - integerの値
                            ; - *

16  call     2              ; スタックの最初の要素の2つ
                            ; (先頭の2つ)を引数として
                            ; 関数*を呼び出し
                            ; 結果をスタックに積む

17  return                  ; スタックの先頭要素を返す
     => nil

関数silly-loopは、少々複雑です。

(defun silly-loop (n)
  "Return time before and after N iterations of a loop."
  (let ((t1 (current-time-string)))
    (while (> (setq n (1- n))
              0))
    (list t1 (current-time-string))))
     => silly-loop

(disassemble 'silly-loop)
     -| byte-code for silly-loop:
 doc: Return time before and after N iterations of a loop.
 args: (n)

0   constant current-time-string  ; current-time-stringを
                                  ; スタックの先頭に積む

1   call     0              ; 引数なしでcurrent-time-stringを
                            ; 呼び出し、結果をスタックに積む

2   varbind  t1             ; スタックから値を取りさり、
                            ; t1に束縛する

3   varref   n              ; 環境からnの値を取得し、
                            ; 値をスタックに積む

4   sub1                    ; スタックの先頭から1を引く

5   dup                     ; スタックの先頭の値を複製する
                            ; つまり、スタックの先頭の値を
                            ; コピーして、それをスタックに積む

6   varset   n              ; スタックの先頭から値を取りさり、
                            ; 値をnに束縛する

                            ; つまり、dup varsetは
                            ; スタックの先頭の値を取りさらずに
                            ; nにコピーする

7   constant 0              ; スタックに0を積む

8   gtr                     ; スタックから2つの値を取りさり、
                            ; nが0より大きいか調べ、
                            ; 結果をスタックに積む

9   goto-if-nil-else-pop 17 ; n <= 0ならば17へ飛ぶ
                            ; (whileループから抜ける)
                            ; さもなければ、スタックの先頭から
                            ; 値を取りさり、つぎへ進む

12  constant nil            ; スタックにnilを積む
                            ; (これはループの本体)

13  discard                 ; ループの本体の結果を捨てる
                            ; (whileループは副作用のために
                            ; つねに評価される)

14  goto     3              ; whileループの先頭へ飛ぶ

17  discard                 ; スタックの先頭の値を取りさって、
                            ; whileループの結果を捨てる。
                            ; これは、9での飛び越しのために
                            ; 取りさっていない値nil

18  varref   t1             ; t1の値をスタックに積む

19  constant current-time-string  ; current-time-stringを
                                  ; スタックに積む

20  call     0              ; ふたたびcurrent-time-stringを
                            ; 呼び出す

21  list2                   ; スタックの先頭から2つの値を取りさり
                            ; それらのリストを作り、
                            ; リストをスタックに積む

22  unbind   1              ; ローカルの環境のt1の束縛を解く

23  return                  ; スタックの先頭の値を返す

     => nil


Node:Advising Functions, Next:, Previous:Byte Compilation, Up:Top

Emacs Lisp関数のアドバイス

アドバイス(advice)機能により、関数の既存の定義に追加できます。 これは、Emacsの他の部分で定義された関数を ライブラリにおいてカスタマイズする見通しのよい方法です。 関数全体を再定義するよりも見通しがよいのです。

各関数は、個別に定義した複数のアドバイス断片を持てます。 それぞれのアドバイス断片は、明示的に有効にしたり無効にできます。 任意の関数の有効にしたアドバイス断片が実際にその効果を発揮するのは、 当該関数のアドバイスを活性にしたときか 当該関数をのちに定義したり再定義したときです。

使用上の注意: アドバイスは、既存関数の既存の呼び出しのふるまいを変更するのに有用である。 新たな呼び出しやキーバインドの新たなふるまいが必要な場合には、 既存関数を使う新たな関数(や新たなコマンド)を定義するほうが 見通しがよい。


Node:Simple Advice, Next:, Up:Advising Functions

単純なアドバイスの例

コマンドnext-lineは、ポイントを垂直に複数行移動します。 標準バインドはC-nです。 バッファの最終行で使うと、 (next-line-add-newlinesnil以外の場合) このコマンドは行を作るために改行を挿入し、その行に移動します。

同様な機能をprevious-lineに追加したいとします。 つまり、バッファの先頭に新たな行を挿入し、その行へ移動するのです。 どのようにすればよいでしょう?

当該関数を再定義すればできますが、それではモジュール性がよくありません。 アドバイス機能が見通しのよい代替方法を提供します。 既存の関数定義を実際に変更したりその定義を参照することなく、 関数定義に読者のコードを実質的に追加できます。 つぎのように行います。

(defadvice previous-line (before next-line-at-end (arg))
  "Insert an empty line when moving up from the top line."
  (if (and next-line-add-newlines (= arg 1)
           (save-excursion (beginning-of-line) (bobp)))
      (progn
        (beginning-of-line)
        (newline))))

この式は、関数previous-lineに対するアドバイス断片を定義します。 このアドバイス断片にはnext-line-at-endという名前が付きます。 シンボルbeforeにより、 previous-lineの通常の定義を実行するまえに実行する 事前アドバイス(before-advice)であることを意味します。 (arg)は、アドバイス断片がどのように関数の引数を参照するかを指定します。

このアドバイス断片が実行されると、必要な場面では新たに行を作りますが、 その行へはポイントを移動しません。 これはアドバイスを書く正しいやりかたです。 というのは、通常の定義がこのあとに実行され、新たに挿入した行へ移動します。

アドバイスを定義しても関数previous-lineをただちには変更しません。 つぎのようにアドバイスを活性にすると変わります。

(ad-activate 'previous-line)

これにより、関数previous-lineに対して定義してある アドバイスを使い始めます。 これ以降、C-pM-xでユーザーが起動したのか Lispから呼ばれたのかに関わらず、 この関数を起動すると、まずアドバイスを実行してから 関数の通常の定義を実行します。

この例は、アドバイスの1つのクラスである事前アドバイスの例であり、 関数の元定義のまえに実行されます。 他に2つのアドバイスクラスがあります。 元定義のあとに実行される事後アドバイス(after-advice)と 元定義の起動を包み込む式を指定する包囲アドバイス(around-advice)です。


Node:Defining Advice, Next:, Previous:Simple Advice, Up:Advising Functions

アドバイス定義

アドバイス断片を定義するには、マクロdefadviceを使います。 defadviceの呼び出しはつぎのような構文です。 defundefmacroの構文を基にしていますが、 追加部分があります。

(defadvice function (class name
                         [position] [arglist]
                         flags...)
  [documentation-string]
  [interactive-form]
  body-forms...)

ここで、functionはアドバイス対象となる関数 (やマクロやスペシャルフォーム)です。 以後、アドバイスする対象を単に『関数』と書きますが、 これにはつねにマクロやスペシャルフォームを含みます。

classはアドバイスのクラスを指定し、 beforeafteraroundのいずれかです。 事前アドバイス(before)は関数そのもののまえに実行されます。 事後アドバイス(after)は関数そのもののあとに実行されます。 包囲アドバイス(around)は関数自身の実行を包み込みます。 事後アドバイスと包囲アドバイスでは、 ad-return-valueに設定することで戻り値を変更できます。

ad-return-value Variable
アドバイスを実行しているとき、 関数の元定義の実行を完了したあとでは、この変数はその戻り値を保持する。 すべてのアドバイスを完了すると、最終的には、この値を呼び出し側へ返す。 事後アドバイスと包囲アドバイスでは、この変数に別の値を設定することで 戻り値を変更できる。

引数nameはアドバイスの名前であり、nil以外のシンボルです。 アドバイス名は、functionの特定クラスのすべてのアドバイス断片から 1つのアドバイス断片を一意に識別します。 名前でアドバイス断片を参照でき、 それを再定義したり有効にしたり無効にできます。

通常の関数定義の引数リストのかわりに、 アドバイス定義では異なる情報を必要とします。

省略可能なpositionは、指定したclassの 現在のアドバイスリストのどこに新たなアドバイスを置くかを指定します。 firstlast、あるいは、 0から数え始める位置を指定する数である必要があります (firstは0と等価)。 位置を指定しないとデフォルトはfirstです。 当該クラスの既存位置の範囲を超えている場合には、 先頭か末尾のどちらか近いほうになります。 既存のアドバイス断片を再定義する場合には、値positionは無視されます。

省略可能なarglistは、 アドバイスが使う引数リストを定義するために使います。 これは、アドバイスを実行するために生成される結合定義 (see Combined Definition)の引数リストになります。 その結果、アドバイスの式では、 引数の値を参照するためにこのリストの引数変数を使えます。

この引数リストは、関数の実際の呼び出し方を扱えるように、 もとの関数の引数リストと互換性がある必要があります。 2つ以上のアドバイス断片で引数リストを指定している場合、 すべてのアドバイスクラスの中で最初のもの(位置が最小のもの)を使います。

残りの要素flagsは、このアドバイス断片の使い方に関する情報を指定する シンボルです。 正しいシンボルとそれらの意味はつぎのとおりです。

activate
functionに対するアドバイスをただちに活性にする。 関数のアドバイスに対する変更は、当該関数のアドバイスを活性にすると 効果を持つようになる。 このフラグは、functionに対するこのアドバイス断片を定義した直後に そのようにすることを指示する。

functionが未定義(未定義のアドバイス(forward advice)と呼ぶ状況) であるとこのフラグにはなんの効果もない。 というのは、未定義関数のアドバイスは活性にできないからである。 しかし、functionを定義するとそのアドバイスは自動的に活性にされる。

protect
このアドバイス断片をそれよりまえに実行されるコードやアドバイスによる 非ローカル脱出やエラーに対して保護する。 保護したアドバイス断片は、 フォームunwind-protectの中に後始末として置かれ、 それよりまえに実行されるコードでエラーが発生したりthrowを使っても 実行される。 see Cleanups
compile
アドバイスの実行に使われる結合定義をコンパイルする。 activateとともに指定しないと、このフラグは無視する。 see Combined Definition
disable
このアドバイス断片を当初は無効にしておき、 のちに明示的に有効にしない限り使われない。 see Enabling Advice
preactivate
このdefadviceをコンパイルしたりマクロ展開したときに、 functionに対するアドバイスを活性にする。 これにより現在のアドバイスの状態に応じたアドバイス定義をコンパイルし、 必要に応じて使われるようになる。

このdefadviceをバイトコンパイルする場合にのみ意味を持つ。

省略可能なdocumentation-stringは、 このアドバイス断片の説明文字列になります。 functionに対するアドバイスが活性であると、 (documentationが返す)functionの説明文は、 関数の元定義の説明文字列とfunctionのアドバイスすべての説明文字列の 合成になります。

省略可能なinteractive-formは、 元関数の対話的ふるまいを変更するために指定します。 2つ以上のアドバイス断片でinteractive-formを指定している場合、 すべてのアドバイスの中で最初のもの(位置が最小のもの)が優先します。

空リストでもかまわないbody-formsは、アドバイスの本体です。 アドバイスの本体では、引数、戻り値、束縛環境を参照/変更したり、 いかなる種類の副作用を起こせます。

警告: マクロをアドバイスする場合、 マクロはプログラムのコンパイル時に展開されるのであって、 コンパイルしたプログラムの実行時に展開されるのではないことに注意。 アドバイスが使用するすべてのサブルーティンは、 バイトコンパイラがマクロを展開するときに必要になる。


Node:Around-Advice, Next:, Previous:Defining Advice, Up:Advising Functions

包囲アドバイス

包囲アドバイスにより、関数の元定義を包み込むLisp式を書けます。 関数の元定義を実行する場所を特別なシンボルad-do-itで指定します。 包囲アドバイスの本体に現れたこのシンボルは、 元定義(と内側の包囲アドバイス本体)のフォームを含んだprognで 置き換えられます。 例を示しましょう。

(defadvice foo (around foo-around)
  "Ignore case in `foo'."
  (let ((case-fold-search t))
    ad-do-it))

これは、fooの元定義を実行するときに 大文字小文字を区別しないで探索することを保証します。

ad-do-it Variable
これは実際には変数ではないが、包囲アドバイス内では変数のように用いる。 関数の元定義と『より内側の』包囲アドバイスを実行する場所を指定する。

包囲アドバイスでad-do-itを用いなければ、関数の元定義を実行しません。 これは、元定義を完全に無効にする手段です。 (さらに、内側の包囲アドバイス断片も無効にする。)


Node:Computed Advice, Next:, Previous:Around-Advice, Up:Advising Functions

計算アドバイス

マクロdefadvicedefunに似ていて、 アドバイスのコードやアドバイスに関する他のすべての情報を ソースコードで明示します。 関数ad-add-adviceを用いると、 その詳細を計算で求めたアドバイスを作成できます。

ad-add-advice function advice class position Function
ad-add-adviceを呼び出すと、 関数functionに対するクラスclassのアドバイス断片として adviceを追加する。 引数adviceはつぎの形式である。
(name protected enabled definition)

ここで、protectedenabledはフラグであり、 definitionはアドバイスの動作を指定する式である。 enablednilであると、 このアドバイス断片は当初は無効になる (see Enabling Advice)。

functionに指定したクラスclassのアドバイス断片がすでにあると、 positionは新しいアドバイス断片をリストのどこに置くかを指定する。 positionの値は、firstlast、あるいは、 (リストの先頭を0から数えた)数である。 範囲外の数は先頭か末尾のどちらか近いほうになる。

functionに同じ名前のアドバイス断片adviceがすでにあると、 引数positionは無視され、古いアドバイス断片を新しいもので置き換える。


Node:Activation of Advice, Next:, Previous:Computed Advice, Up:Advising Functions

アドバイスの活性化

デフォルトでは、アドバイスを定義してもその効果は発揮されません。 アドバイスした関数のアドバイスを活性にして始めて効果を発揮します。 defadviceでフラグactivateを指定すれば、 関数にアドバイスを定義したときに活性にできます。 しかし、普通は、関数ad-activateや以下の活性化コマンドを 呼び出すことで、関数のアドバイスを活性にします。

アドバイスの定義操作と活性化操作を区別することで、 アドバイスを追加するたびに関数を再定義することなる、 関数に複数のアドバイス断片を効率よく追加できます。 さらに重要なことは、関数を実際に定義するまえでも 関数にアドバイスを定義できることです。

関数のアドバイスを初めて活性にすると、 関数の元定義を保存してから、関数に対する有効なアドバイス断片すべてを 元定義と結合して新たな定義を作り出します。 (現在無効にしてあるアドバイス断片は使用しない。 see Enabling Advice。) この定義をインストールし、 以下に述べる条件に応じてバイトコンパイルする場合もあります。

アドバイスを活性にするコマンドすべてにおいて、 compiletであると、 アドバイスを実装する結合定義をコンパイルします。

ad-activate function &optional compile コマンド
このコマンドはfunctionに対するアドバイスを活性にする。

関数のアドバイスがすでに活性になっているアドバイスを 活性にしても意味があります。 当該関数のアドバイスを活性にしたあとでアドバイスを変更した場合、 その変更が効果を持つようにする操作になります。

ad-deactivate function コマンド
このコマンドはfunctionのアドバイスを不活性にする。

ad-activate-all &optional compile コマンド
このコマンドはすべての関数に対するアドバイスを活性にする。

ad-deactivate-all コマンド
このコマンドはすべての関数に対するアドバイスを不活性にする。

ad-activate-regexp regexp &optional compile コマンド
このコマンドはregexpに一致する名前のすべてのアドバイス断片を活性にする。 より正確には、regexpに一致する名前のアドバイス断片を持つ任意の 関数のすべてのアドバイスを活性にする。

ad-deactivate-regexp regexp コマンド
このコマンドはregexpに一致する名前の すべてのアドバイス断片を不活性にする。 より正確には、regexpに一致する名前のアドバイス断片を持つ任意の 関数のすべてのアドバイスを不活性にする。

ad-update-regexp regexp &optional compile コマンド
このコマンドはregexpに一致する名前のアドバイス断片を活性にするが、 すでにアドバイスが活性になっている関数に対するものだけである。

関数に対するアドバイスの再活性化は、 アドバイスを活性にしたあとに行った当該アドバイスの変更すべて (有効にしたり無効にしたアドバイス断片を含む。 see Enabling Advice)が効果を持つようにするのに便利である。

ad-start-advice コマンド
関数を定義したり再定義したときにアドバイスを自動的に活性にする。 このモードをオンにすると、アドバイスを定義するとただちに効果を持つようになる。

ad-stop-advice コマンド
関数を定義したり再定義してもアドバイスを自動的には活性にしない。

ad-default-compilation-action User Option
この変数は、関数に対するアドバイスを活性にした結果作られる 結合定義をコンパイルするかどうか制御する。

『予約活性』(see Preactivation)中にアドバイス定義を作成すると その定義はすでにコンパイルされているはずです。 というのは、preactivateフラグを指定したdefadviceを 含むファイルをバイトコンパイル中にそれが定義されたはずだからです。


Node:Enabling Advice, Next:, Previous:Activation of Advice, Up:Advising Functions

アドバイスの有効化と無効化

各アドバイス断片には、 それを有効にするか無効にするかを指定するフラグがあります。 アドバイス断片を有効にしたり無効にすることで、 アドバイス断片を未定義にしたり再定義することなくオン/オフできます。 たとえば、関数fooに対するアドバイス断片my-adviceを 無効にするには、つぎのようにします。

(ad-disable-advice 'foo 'before 'my-advice)

この関数自身は、アドバイス断片の有効化フラグを変更するだけです。 アドバイスした関数でこの変更の効果を発揮するには、 fooのアドバイスを再度活性にする必要があります。

(ad-activate 'foo)

ad-disable-advice function class name コマンド
このコマンドはfunctionに対するクラスclass内の nameで指名したアドバイス断片を無効にする。

ad-enable-advice function class name コマンド
このコマンドはfunctionに対するクラスclass内の nameで指名したアドバイス断片を有効にする。

正規表現を用いて、さまざまな関数に対する 多数のアドバイス断片を一度に無効にすることもできます。 この場合も、当該関数のアドバイスを再度活性にすることで、 その効果が発揮されます。

ad-disable-regexp regexp コマンド
このコマンドは、すべての関数のすべてのクラスの regexpに一致するアドバイス断片すべてを無効にする。

ad-enable-regexp regexp コマンド
このコマンドは、すべての関数のすべてのクラスの regexpに一致するアドバイス断片すべてを有効にする。


Node:Preactivation, Next:, Previous:Enabling Advice, Up:Advising Functions

予約活性

アドバイスを実行するための結合定義を作成することは、 ある程度手間がかかります。 ライブラリで多数の関数をアドバイスしていると、 ライブラリのロードが遅くなります。 そのような場合、あらかじめ適切な結合定義を作成する 予約活性(preactivation)を使えます。

予約活性を使うには、defadviceでアドバイスを定義するときに フラグpreactivateを指定します。 このようなdefadviceの呼び出しでは、 (有効か無効に関わらず)このアドバイス断片と 当該関数に対して現在有効になっている他のアドバイスを元定義 に結合した定義を作成します。 defadviceをコンパイルすると、その結合定義もコンパイルします。

のちに関数のアドバイスを活性にしたとき、 関数に対する有効にしたアドバイスがこの結合定義の作成に 使用したものに一致すると既存の結合定義を使います。 そのため、新たに結合定義を作成する必要がなくなります。 したがって、予約活性はけっしてまちがった結果を生じませんが、 予約活性に用いたアドバイスと活性にした有効なアドバイスが一致しないと 利点はなくなります。

不一致のために予約活性が正しく動作していない兆候の例を示します。

関数自体が定義されるまえであってもコンパイル済みの予約活性したアドバイスは 正しく動作します。 しかし、予約活性したアドバイスをコンパイルするときには 関数は定義済みである必要があります。

予約活性したアドバイスが使われない理由を調べるよい方法はありません。 できることは、 関数のアドバイスを活性にするまえに、 (関数trace-function-backgroundで) 関数ad-cache-id-verification-codeをトレースすることです。 活性にしたあと、当該関数に対してad-cache-id-verification-codeが 返した値を調べます。 verifiedならば予約活性したアドバイスが使われています。 これ以外の値は、アドバイスが不適切と判断された理由に関する情報を 与えます。

警告: 予約活性が失敗する場合が1つ知られている。 現在のアドバイスの状態に一致しなくても、 あらかじめ作成した結合定義を使ってしまう。 これは、同一関数に対する同じクラスの同一名称であるが異なるアドバイス断片を 2つのパッケージで定義している場合に発生する。 このようなことは避けること。


Node:Argument Access in Advice, Next:, Previous:Preactivation, Up:Advising Functions

アドバイスからの引数の参照

アドバイス断片の本体からアドバイスする関数の引数を参照する もっとも簡単な方法は、関数定義で用いているものと同じ名前を使うことです。 これには、元関数の引数の変数名を知る必要があります。

多くの場合、この単純な方法で十分ですが、欠点もあります。 アドバイス内に引数名を直接書き込むために、堅牢ではありません。 関数の元定義が変更されると、アドバイスは動作しません。

他の方法は、アドバイスそのものに引数リストを指定することです。 これは関数の元定義の引数名を知る必要はありませんが、制約もあります。 関数に対するすべてのアドバイスで同一の引数リストを使う必要があります。 なぜなら、すべてのアドバイスに実際に使われる引数リストは、 当該関数のアドバイス断片の最初のものだからです。

より堅牢な方法は、活性にするときに、 つまり、アドバイスを結合した定義を作成するときに 適切なフォームに展開されるマクロを使うことです。 参照用マクロは、関数の引数変数への実引数の分配方法に依存しない 実引数の位置で参照します。 Emacs Lispにおいては、引数の意味は引数リスト内での位置で決まるため、 これは堅牢です。

ad-get-arg position Macro
位置positionにある実引数を返す。

ad-get-args position Macro
位置positionから始まる実引数のリストを返す。

ad-set-arg position value Macro
位置positionにある実引数の値を設定する。

ad-set-args position value-list Macro
位置positionから始まる実引数のリストにvalue-listを設定する。

例を示します。 関数fooの定義はつぎのとおりであり、

(defun foo (x y &optional z &rest r) ...)

つぎのように呼ばれるとします。

(foo 0 1 2 3 4 5 6)

そうすると、fooの本体では、 xは0、yは1、zは2、r(3 4 5 6)です。 このとき、ad-get-argad-get-argsは、つぎの値を返します。

(ad-get-arg 0) => 0
(ad-get-arg 1) => 1
(ad-get-arg 2) => 2
(ad-get-arg 3) => 3
(ad-get-args 2) => (2 3 4 5 6)
(ad-get-args 4) => (4 5 6)

この例では、引数に値を設定できます。

(ad-set-arg 5 "five")

の効果は、6番目の引数を"five"に変更します。 fooの本体を実行するまえにこのアドバイスが実行されると、 本体内ではr(3 4 "five" 6)になります。

つぎは引数リストを変更する例です。

(ad-set-args 0 '(5 4 3 2 1 0))

fooの本体を実行するまえにこのアドバイスが実行されると、 fooの本体内では、 xは5、yは4、zは3、r(2 1 0)になります。

これらの引数参照は、実際にはLispマクロとしての実装ではありません。 アドバイス機構で特別に実装してあります。


Node:Subr Arguments, Next:, Previous:Argument Access in Advice, Up:Advising Functions

subr引数リストの定義

アドバイス機能が結合定義を作成するとき、 元関数の引数リストを知る必要があります。 基本関数に対しては、これはつねに可能とは限りません。 アドバイスが引数リストを決定できないときには、 (&rest ad-subr-args)を使います。 これはつねに動作しますが、 引数値のリストを作成するために効率的ではありません。 ad-define-subr-argsを使って、 基本関数に対する適当な引数名を宣言できます。

ad-define-subr-args function arglist Function
この関数は、関数functionの引数リストとして arglistを使うことを指定する。

たとえば、

(ad-define-subr-args 'fset '(sym newdef))

は、関数fsetの引数リストを指定します。


Node:Combined Definition, Previous:Subr Arguments, Up:Advising Functions

結合定義

関数には、n個の事前アドバイス(before-advice)、 m個の包囲アドバイス(around-advice)、 k個の事後アドバイス(after-advice)があるとします。 保護したアドバイス断片はないと仮定すると、 関数のアドバイスを実装するために作成される結合定義は つぎのようになります。

(lambda arglist
  [ [advised-docstring] [(interactive ...)] ]
  (let (ad-return-value)
    before-0-body-form...
         ....
    before-n-1-body-form...
    around-0-body-form...
       around-1-body-form...
             ....
          around-m-1-body-form...
             (setq ad-return-value
                   apply original definition to arglist)
          other-around-m-1-body-form...
             ....
       other-around-1-body-form...
    other-around-0-body-form...
    after-0-body-form...
          ....
    after-k-1-body-form...
    ad-return-value))

マクロはマクロとして再定義します。 つまり、結合定義の先頭にmacroを追加します。

元関数やアドバイス断片のどれかに対話宣言があれば、 対話宣言フォームが入ります。 対話的な基本関数をアドバイスした場合には、 特別な方法を使います。 つまり、基本関数をcall-interactivelyで呼び出して、 基本関数自身が引数を読み取るようにします。 この場合、アドバイスからは引数を参照できません。

各クラスのさまざまなアドバイスの本体フォームは、 それらの指定された順に組み立てられます。 包囲アドバイスl(around-advice l)のフォーム群は、 包囲アドバイスl - 1(around-advice l - 1)の フォームの1つに入ります。

包囲アドバイスのもっとも内側では、

元定義をarglistに適用

しますが、そのフォームは元関数の種類に依存します。 変数ad-return-valueには、その戻り値が設定されます。 この変数はすべてのアドバイス断片から見えるので、 アドバイスした関数から実際に戻るまえに、 これを参照したり変更できます。

保護したアドバイス断片を含むアドバイスした関数の構造も同じです。 唯一の違いは、フォームunwind-protectにより、 アドバイス断片でエラーを起こしたり非ローカル脱出を行っても、 保護したアドバイスが実行されることを保証します。 包囲アドバイスを1つでも保護していると、その結果として、 包囲アドバイス全体が保護されます。


Node:Debugging, Next:, Previous:Advising Functions, Up:Top

Lispプログラムのデバッグ

Emacs Lispプログラムの問題点を調べるには、 問題が発生したときにどのようにプログラムを使っているかに依存して、 3つの方法があります。

他の有用なデバッグツールは、ドリブルファイルです。 ドリブルファイルをオープンしてあると、 Emacsはすべてのキーボード入力をこのファイルにコピーします。 あとでこのファイルを調べれば、どんな入力があったかわかります。 See Terminal Input

端末設定に関した問題を解決するには、 関数open-termscriptが有用です。 See Terminal Output


Node:Debugger, Next:, Up:Debugging

Lispデバッガ

通常のLispデバッガは、フォームの評価を一時停止する機能を提供します。 評価を一時停止しているあいだ(ブレーク(break)と呼ばれる状態)は、 実行時スタックを調べたり、ローカルやグローバル変数の値を調べたり、 それらの値を変更できます。 ブレークは再帰編集なので、Emacsの通常の編集機能すべてを使えます。 デバッガを再帰的に起動するようなプログラムを実行することさえできます。 See Recursive Editing


Node:Error Debugging, Next:, Up:Debugger

エラーによるデバッガの起動

デバッガへ入るもっとも重要な時期は、Lispエラーが発生したときです。 これにより、エラーの直接原因を調べることができます。

しかし、デバッガに入るのは、エラーの通常の帰結ではありません。 多くのコマンドは (バッファの末尾でC-fを使うなどの)不適切に起動されると しばしばLispエラーを生じますが、 通常の編集ではそのたびにデバッガに入ったのではとても不便です。 そのため、エラーによってデバッガに入りたい場合には、 変数debug-on-errornil以外を設定します。 (コマンドtoggle-debug-on-errorはこれを簡単に行う。)

debug-on-error User Option
この変数は、エラーが通知され処理されないときに デバッガを呼び出すかどうか決定する。 debug-on-errortであると、 すべての種類のエラー(debug-ignored-errorsに指定したものを除く) はデバッガを呼び出す。 nilであるとデバッガを呼び出さない。

その値はデバッガを呼び出すエラー条件のリストでもよい。 たとえば、リスト(void-variable)にすると、 「値を持たない変数に関したエラー」のみがデバッガを起動する。

この変数がnil以外であると、 Emacsはプロセスのフィルタ関数や番兵に対してエラーハンドラを作成しない。 したがって、これらの関数でのエラーもデバッガを起動する。 see Processes

debug-ignored-errors User Option
この変数は、デバッガに入らないエラーの種類を指定する。 その値はエラー条件シンボルや正規表現のリストである。 エラーにこれらの条件シンボルが含まれるか エラーメッセージが正規表現の1つに一致する場合には、 debug-on-errorの値に関わらず 当該エラーではデバッガに入らない。

この変数の通常の値は、 編集ではしばしば発生するが、Lispプログラムのバグではほとんど発生しないような エラー群のリストである。 しかし、『ほとんど』は『けっして』ではない。 このリストに一致するようなエラーで読者のプログラムが失敗する場合、 エラーをデバッグするにはこのリストを変更する必要がある。 もっとも簡単な方法は、debug-ignored-errorsnilを 設定することである。

debug-on-signal User Option
通常、condition-caseで捕捉したエラーは、 たとえdebug-on-errornil以外であっても、 けっしてデバッガを起動しない。 いいかえれば、デバッガを起動するまえに、 condition-caseはエラー処理の機会を得るのである。

debug-on-signalnil以外の値を設定すると、 各エラーごとにデバッガがまず機会を得る。 debug-on-errordebug-ignored-errorsの値で指定される 条件に一致すれば、condition-caseに関わらず エラーはデバッガを起動する。

警告: この変数は強力な処方である! Emacsのさまざまな部分では通常の動作としてエラーを処理し、 読者にはエラーが発生したことさえわからない。 debug-on-signalnil以外の値を設定すると それらのエラーでデバッガに入る。

警告: debug-on-errornilであると、 debug-on-signalは意味を持たない。

ファイル.emacsをロード中に発生するエラーをデバッグするには、 オプション--debug-initを使います。 これにより、.emacsのロード中はdebug-on-errortに束縛し、 初期化ファイルでのエラーを捕捉するcondition-caseを迂回します。

読者のファイル.emacsdebug-on-errorを設定しても、 その効果は.emacsのロードを終ると持続しません。 (これはコマンド行オプション--debug-initの実装における 好ましくない特性である。) .emacsdebug-on-errorを恒久的に設定する最良の方法は、 つぎのように、after-init-hookを用いることです。

(add-hook 'after-init-hook
          '(lambda () (setq debug-on-error t)))


Node:Infinite Loops, Next:, Previous:Error Debugging, Up:Debugger

無限ループのデバッグ

プログラムが無限にループし戻ってこないときには、 まず、ループを停止する必要があります。 ほとんどのオペレーティングシステムでは、 中断を意味するC-gを使います。

普通に中断したのでは、 プログラムが無限ループした理由に関する情報は得られません。 より詳しい情報を得るには、 変数debug-on-quitnil以外を設定します。 C-gによる中断はエラーとは扱わないため、 C-gの処理に関してdebug-on-errorはなんの効果もありません。 同様に、debug-on-quitはエラーに関してなんの効果もありません。

無限ループの途中でデバッガを起動できれば、 デバッガでステップ実行コマンドを使って先へ進めます。 ループひとまわりをステップ実行すれば、 問題を解決するに十分な情報を得られるはずです。

debug-on-quit User Option
この変数は、quitが通知され処理されなかった場合に、 デバッガを呼び出すかどうかを決定する。 debug-on-quitnil以外である場合、 (C-gを打って)中断するとデバッガを呼び出す。 debug-on-quitnilであると、 中断してもデバッガを呼び出さない。 see Quitting


Node:Function Debugging, Next:, Previous:Infinite Loops, Up:Debugger

関数呼び出し時のデバッガの起動

プログラムの途中で発生する問題点を調べるための1つの有用な技法は、 ある関数を呼び出すたびにデバッガに入ることです。 問題を生じる関数に対してこのようにしておき、 当該関数をステップ実行するか、あるいは、 問題が発生する直前に呼ばれる関数に対してこのようにしておき、 その関数の呼び出しを終えてから、呼び出し側をステップ実行します。

debug-on-entry function-name コマンド
この関数は、function-nameが呼び出されるたびに デバッガを起動するようにする。 当該関数の定義の最初のフォームとして フォーム(debug 'debug)を挿入することでこれを行う。

Lispコードで定義した任意の関数は、 解釈実行コードであろうとコンパイル済みのコードであろうと、 関数に入るときにブレークするようにできる。 関数がコマンドであると、Lispから呼ばれたときや 対話的に呼ばれたときに(引数を読み取ってから)デバッガに入る。 (Cで書いた)基本関数は、この方法ではデバッグできない。

debug-on-entryを対話的に呼び出すと、 ミニバッファでfunction-nameを問い合わせる。 その関数がすでに呼び出し時にデバッガを起動するようになっていると、 debug-on-entryはなにもしない。 debug-on-entryはつねにfunction-nameを返す。

注意: debug-on-entryを使ったあとに当該関数を再定義すると、 デバッガに入るためのコードがなくなる。 実質的には、関数を再定義すると呼び出し時にブレークする機能を 取り消すことになる。

(defun fact (n)
  (if (zerop n) 1
      (* n (fact (1- n)))))
     => fact
(debug-on-entry 'fact)
     => fact
(fact 3)

------ Buffer: *Backtrace* ------
Entering:
* fact(3)
  eval-region(4870 4878 t)
  byte-code("...")
  eval-last-sexp(nil)
  (let ...)
  eval-insert-last-sexp(nil)
* call-interactively(eval-insert-last-sexp)
------ Buffer: *Backtrace* ------

(symbol-function 'fact)
     => (lambda (n)
          (debug (quote debug))
          (if (zerop n) 1 (* n (fact (1- n)))))

cancel-debug-on-entry function-name コマンド
この関数は、function-nameに対するdebug-on-entryの効果 (呼び出し時にブレークする)を取り消す。 対話的に呼び出すと、 ミニバッファでfunction-nameを問い合わせる。 function-namenilであったり空文字列であると、 すべての関数について、呼び出し時にブレークすることを取り消す。

呼び出し時にブレークする設定をしていない関数に対して cancel-debug-on-entryを呼び出してもなにもしない。 つねにfunction-nameを返す。


Node:Explicit Debug, Next:, Previous:Function Debugging, Up:Debugger

デバッガの明示的な起動

読者のプログラムに式(debug)を書くと、 その箇所でデバッガを呼び出すことができます。 つまり、ソースファイルを訪問して適当な箇所にテキスト(debug)を挿入し、 C-M-xと打ちます。 警告: 一時的なデバッグ目的でこれを行う場合には、 ファイルを保存するまえにこの挿入箇所をもとに戻すこと!

(debug)を挿入する箇所は、 余分なフォームを評価してもその値を無視できる場所でなければなりません。 ((debug)の値が無視されないと、 プログラムの実行を変えてしまう!) もっとも適した一般的な場所はprognや暗黙のprognの内側です (see Sequencing)。


Node:Using Debugger, Next:, Previous:Explicit Debug, Up:Debugger

デバッガの使い方

デバッガに入ると、それまで選択していたバッファをあるウィンドウに、 *Backtrace*という名前のバッファを別のウィンドウに表示します。 バックトレースバッファでは、各行は現在実行中のLisp関数の各レベルです。 このバッファの先頭には、デバッガを起動するに至った理由 (エラーで起動されたときにはエラーメッセージと関連データ) を表すメッセージがあります。

バックトレースバッファは読み出し専用であり、 各文字をデバッガコマンドであると定義した 特別なメジャーモード、debuggerモードを使います。 Emacsの通常の編集コマンドも使えます。 したがって、エラー発生時に編集していたバッファを調べるためにウィンドウを 切り替えたり、バッファを切り替えたり、ファイルを訪れたり、 その他のどんな編集でもできます。 しかし、デバッガは再帰編集レベル(see Recursive Editing)であるので、 デバッグを終えるときには、バックトレースバッファに戻ってから デバッガを(コマンドqで)終了するのが賢い方法です。 デバッガを終了すると、再帰編集から抜けバックトレースバッファを削除します。

バックトレースバッファでは、実行中の関数とその引数の値を表示します。 また、スタックフレームを記述する行へポイントを移動することで スタックフレームを指定できます。 (スタックフレームとは、Lispインタープリタが関数の起動に関する情報を 記録しておく場所である。) ポイントがある行に対応するフレームをカレントフレーム(current frame)と 呼びます。 デバッガのある種のコマンドはカレントフレームに作用します。

デバッガ自身はバイトコンパイルしたものを実行する必要があります。 というのは、デバッガ自身が使用するスタックフレームのサイズを 仮定しているからです。 解釈実行だとこの仮定が成り立ちません。


Node:Debugger Commands, Next:, Previous:Using Debugger, Up:Debugger

デバッガコマンド

デバッガ内(debuggerモード)では、 通常のカーソル移動コマンドに加えて以下の特別なコマンドを使えます。 (ウィンドウやバッファの切り替えなどのEmacsの通常の機能も使えることに留意。)

デバッガコマンドのもっとも重要な使い方はステップ実行であり、 これにより制御の流れを調べることです。 デバッガは、解釈実行版の関数の制御構造をステップ実行できますが、 バイトコンパイルした関数ではできません。 バイトコンパイルした関数をステップ実行したい場合には、 同じ関数を解釈実行版の定義に置き換える必要があります。 (これには、関数のソースを訪れて、その定義内でC-M-xと打つ。)

debuggerモードのコマンド一覧を以下に示します。

c
デバッガを終了し実行を継続する。 継続可能であれば、 (デバッガ内で行った変数値やデータ構造に対する変更などの副作用を除いて) デバッガを起動しなかったかのようにプログラムの実行を再開する。

継続が可能なのは、 関数呼び出し時や終了時、明示的な起動、中断によりデバッガに入った場合である。 エラーが原因でデバッガが起動されたときには継続できない。

d
実行を継続するが、任意のLisp関数を呼び出すとデバッガに入る。 これにより、式の部分式をステップ実行して 部分式が計算する値やその動作を調べることができる。

このようにしてデバッガを起動した関数呼び出しのスタックフレームには 自動的に印が付き、そのスタックから抜けるとデバッガがふたたび呼び出される。 この印を消すにはコマンドuを使う。

b
フレームから抜けるとデバッガに入るようにカレントフレームに印を付ける。 このように印を付けたフレームには、バックトレースバッファでは星印が付く。
u
カレントフレームから抜けるときにデバッガに入らない。 これは、当該フレームに対するコマンドbを取り消す。 視覚的にはバックトレースバッファの当該行から星印が取られる。
e
ミニバッファでLisp式を読み取り、それを評価し、その値をエコー領域に表示する。 この操作の一環として、デバッガは重要なある種の変数や カレントバッファを変更する。 eはそれらの値をデバッガの外側の値に一時的に復元するので、 それらを調べたり変更したりできる。 これによりデバッガは透過的になる。 対照的に、M-:はデバッガ内で特別なことは行わない。 デバッガ内での変数値を表示する。
R
eと同様であるが、 バッファ*Debugger-record*での評価結果も保存する。
q
デバッグ中のプログラムを終了する。 Emacsのトップレベルのコマンド実行へ戻る。

C-gでデバッガへ入ったが、 実際には中断したいのであってデバッグはしたくない場合には コマンドqを使う。

r
デバッガから値を指定して戻る。 その値は、ミニバッファで式を読み取り、それを評価して得る。

bで指定したりdでフレームに入ることで) Lispの呼び出しフレームから抜けでたためにデバッガが起動された場合に、 コマンドrは有用である。 コマンドrで指定した値は、当該フレームの値として使われる。 このコマンドは、debugを呼び出してその戻り値を使う場合にも有用である。 さもなければ、rcと同じ効果であり、指定した戻り値は関係ない。

エラーでデバッガに入った場合にはrは使えない。


Node:Invoking the Debugger, Next:, Previous:Debugger Commands, Up:Debugger

デバッガの起動

ここでは、デバッガを起動するために使われる関数debugの詳細を述べます。

debug &rest debugger-args Function
この関数はデバッガに入る。 *Backtrace*(あるいはデバッガの第2レベルに再帰的に入ると *Backtrace*<2>など)という名前のバッファに切り替え、 Lisp関数の呼び出しスタックに関する情報でこのバッファを満たす。 そして再帰編集に入りdebuggerモードのバックトレースバッファを表示する。

debuggerモードのコマンドcrで再帰編集から抜けだし、 debugはそれ以前のバッファに切り替え debugを呼び出したところへ戻る。 これは、関数debugが呼び出し側へ戻る唯一の手段である。

debugger-argsの使い途は、 debugが引数の残りをバッファ*Backtrace*の先頭に表示し、 ユーザーが読めるようにすることである。 以下に述べる場合を除いて、これがこれらの引数の唯一の用途である。

debugの第1引数が特定の値を持つ場合、特別な意味がある。 (通常、これらの値はEmacs内部で用いるだけであり、 プログラマがdebugを呼ぶときには使わない。) 以下にこれらの特別な値を示す。

lambda
第1引数がlambdaであると、 debug-on-next-callnil以外であるために 関数に入るときにdebugを呼び出したことを意味する。 デバッガはバッファの先頭にテキスト行Entering:を表示する。
debug
第1引数がdebugであると、 関数に入るときにデバッガを起動するようになっていたために debugを呼び出したことを示す。 デバッガは、lambdaの場合と同様に、Entering:を表示する。 さらに、当該関数のスタックフレームに関数から 戻るときにデバッガを起動するように印を付ける。
t
第1引数がtであると、 debug-on-next-callnil以外であるときに フォームの並びを評価したために debugを呼び出したことを示す。 デバッガはバッファの先頭行につぎの行を表示する。
Beginning evaluation of function call form:

exit
第1引数がexitであると、 スタックフレームから抜けるときにデバッガを呼び出すように印を 付けたスタックフレームから抜けたことを示す。 この場合、debugの第2引数はフレームからの戻り値である。 デバッガはバッファの先頭行にReturn value:に続けて戻り値を表示する。
error
第1引数がerrorであると、 エラーやquitが通知されたが処理されないためにデバッガに入ったことを示し、 Signaling:に続けて通知されたエラーとsignalの引数を表示する。 たとえばつぎのとおり。
(let ((debug-on-error t))
  (/ 1 0))

------ Buffer: *Backtrace* ------
Signaling: (arith-error)
  /(1 0)
...
------ Buffer: *Backtrace* ------

エラーが通知されたときには、 変数debug-on-errornil以外であるはずである。 quitが通知されたときには、 変数debug-on-quitnil以外であるはずである。

nil
明示的にデバッガに入るときには、 debugger-argsの先頭としてnilを使う。 debugger-argsの残りはバッファの先頭行に表示される。 この機能を用いてメッセージを表示でき、 たとえば、debugを呼び出した条件の覚え書きにする。


Node:Internals of Debugger, Previous:Invoking the Debugger, Up:Debugger

デバッガの内部

本節では、デバッガが内部的に使用する関数や変数について述べます。

debugger Variable
この変数の値は、デバッガを起動するために呼び出す関数である。 その値は、可変個数の引数を取る関数(あるいは典型的には関数名)であること。 その関数でなんらかのデバッガに入ると仮定する。 この変数のデフォルト値はdebug

Lispが関数に渡す最初の引数で、呼び出した理由を表す。 引数の規約はdebugに記述してある。

backtrace コマンド
この関数は、現在活性なLisp関数呼び出しのトレースを表示する。 これは、debugがバッファ*Backtrace*を 満たすために用いる関数である。 どの関数呼び出しが活性であるかを 判断するためにスタックを参照する必要があるためCで書いてある。 戻り値はつねにnil

以下の例では、Lisp式で明示的にbacktraceを呼び出す。 これにより、バックトレースをストリームstandard-outputに出力する。 ここではバッファbacktrace-outputに出力する。 バックトレースの各行は、1つの関数呼び出しを表す。 関数の引数値すべてが判ればそれらを行に表示する。 それらが計算途中であれば、その旨を行に表示する。 スペシャルフォームの引数は省略する。

(with-output-to-temp-buffer "backtrace-output"
  (let ((var 1))
    (save-excursion
      (setq var (eval '(progn
                         (1+ var)
                         (list 'testing (backtrace))))))))

     => nil

----------- Buffer: backtrace-output ------------
  backtrace()
  (list ...computing arguments...)
  (progn ...)
  eval((progn (1+ var) (list (quote testing) (backtrace))))
  (setq ...)
  (save-excursion ...)
  (let ...)
  (with-output-to-temp-buffer ...)
  eval-region(1973 2142 #<buffer *scratch*>)
  byte-code("...  for eval-print-last-sexp ...")
  eval-print-last-sexp(nil)
* call-interactively(eval-print-last-sexp)
----------- Buffer: backtrace-output ------------

文字*は、 抜け出るときにデバッガを起動する印が付いているフレームを表す。

debug-on-next-call Variable
この変数がnil以外であると、 つぎにevalapplyfuncallを呼び出すまえに デバッガを呼び出すことを指定する。 デバッガに入るとdebug-on-next-callnilに設定する。

デバッガのコマンドdは、この変数を設定することで動作する。

backtrace-debug level flag Function
この関数は、levelの深さのスタックフレームに 値flagに応じてフレームから抜け出るときのデバッガ呼び出しの印を付ける。 flagnil以外であると、 のちに当該フレームから抜けるとデバッガに入る。 非ローカルな脱出で当該フレームから抜けるときにもデバッガに入る。

この関数はデバッガのみが使用する。

command-debug-status Variable
この変数は、現在の対話的コマンドのデバッグ状況を記録する。 コマンドが対話的に呼び出されるたびに、 この変数はnilに束縛される。 デバッガはこの変数に設定することで、 同じコマンドの起動中にデバッガが将来起動された場合に備えて 情報を残すことができる。

デバッガにとっては、通常のグローバル変数ではなくこの変数を使う利点は、 以降のコマンド起動にデータが繰り越さないことである。

backtrace-frame frame-number Function
関数backtrace-frameは、Lispデバッガで使うことを意図している。 深さframe-numberのスタックフレームで進行中の計算に関する情報を返す。

当該フレームで引数の評価を完了していなければ(あるいはスペシャルフォーム)、 値は(nil function arg-forms...)

当該フレームで引数の評価を完了し関数を呼び出していれば、 値は(t function arg-values...)

戻り値において、functionは評価したリストのCARであるか、 マクロ呼び出しではlambda式である。 関数に引数&restがあれば、リストarg-valuesの残りで表現される。

frame-numberが範囲外であると、backtrace-framenilを返す。


Node:Edebug, Next:, Previous:Debugger, Up:Debugging

edebug

edebugはEmacs Lispプログラムのソースレベルデバッガであり、 つぎのことを行えます。

以下の最初の3つの節では、edebugを使うのに十分な情報を与えます。


Node:Using Edebug, Next:, Up:Edebug

edebugの使い方

edebugでLispプログラムをデバッグするには、 デバッグしたいLispコードをまず処置(instrument)しておく必要があります。 これを行う簡単な方法は、関数やマクロの定義にポイントを移動してから、 C-u C-M-x(前置引数を指定したeval-defun)を実行します。 コードを処置する別の方法については、See Instrumenting

関数をいったん処置しておけば、当該関数を呼び出すとedebugを活性にします。 edebugが活性になると実行を停止し、 読者が選択したedebugの実行モードに応じて、 関数をステップ実行したりデバッグコマンドを検査しながら 表示を更新しつつ実行を継続します。 デフォルトの実行モードはステップ実行であり、 いったん実行を停止します。 See Edebug Execution Modes

edebugでは、デバッグ中のLispコードのソースを 表示したEmacsバッファを読者は見ます。 このバッファをソースコードバッファと呼びます。 このバッファは一時的に読み出し専用です。

左端の矢印は、関数の実行中の行を表します。 ポイントの初期位置は関数の実行中の行にありますが、 読者自身がポイントを移動すると変わります。

(以下の)facの定義を処置してから(fac 3)を実行したとすると、 つぎのようになります。 ポイントはifのまえの開き括弧にあります。

(defun fac (n)
=>-!-(if (< 0 n)
      (* n (fac (1- n)))
    1))

edebugが関数内で実行を停止できる箇所を停止位置(stop point)と呼びます。 これらは、リストである各部分式の前後と各変数参照のうしろにあります。 関数facの中にある停止位置をピリオドで示します。

(defun fac (n)
  .(if .(< 0 n.).
      .(* n. .(fac (1- n.).).).
    1).)

ソースコードバッファでは、Emacsのlispモードのコマンドに加えて edebugの特別なコマンドを使えます。 たとえば、つぎの停止位置まで実行するには edebugコマンド<SPC>を打ちます。 facに入ったあとで<SPC>を1回打つと、 つぎのような表示になります。

(defun fac (n)
=>(if -!-(< 0 n)
      (* n (fac (1- n)))
    1))

式のうしろでedebugが実行を停止すると、 式の値をエコー領域に値を表示します。

多用される他のコマンドには、 停止位置にブレークポイントを設定するb、 ブレークポイントに達するまで実行するg、 edebugを終了してトップレベルのコマンドループへ戻るqがあります。 edebugのコマンド一覧を表示するには?を打ちます。


Node:Instrumenting, Next:, Previous:Using Edebug, Up:Edebug

edebug向けの処置

Lispコードのデバッグにedebugを使うためには、 コードをまず処置する必要があります。 コードを処置すると、適当な箇所でedebugを起動する追加のコードを挿入します。

いったんedebugをロードすると、 コマンドC-M-xeval-defun)は再定義されます。 定義内で前置引数を指定して起動すると 定義を評価するまえに処置するようになります。 (ソースコード自体は変更しない。) 変数edebug-all-defsnil以外であると、 前置引数の意味を逆にします。 つまり、前置引数を指定しない限りC-M-xは関数定義を処置します。 変数edebug-all-defsのデフォルト値はnilです。 コマンドM-x edebug-all-defsは変数edebug-all-defsの値を トグルします。

edebug-all-defsnil以外であると、 コマンドeval-regioneval-current-buffereval-bufferも それらが評価する定義を処置します。 同様に、edebug-all-formsは、 定義以外のフォームであってもeval-region任意のフォームを処置するかどうか制御します。 これは、ミニバッファでのロードや評価には適用されません。 コマンドM-x edebug-all-formsはこのオプションをトグルします。

別のコマンドM-x edebug-eval-top-level-formは、 edebug-all-defsedebug-all-formsの値に関わらず 任意のトップレベルのフォームを処置するために使えます。

edebugが動作中は、 コマンドIedebug-instrument-callee)で、 ポイントのうしろのフォームから呼ばれる関数やマクロの定義を 処置済みでなければ処置できます。 これは、edebugが当該関数のソースを探せる場合にのみ可能です。 edebugをロード後には、 eval-regionは、処置していないものも含めて、 評価した各定義の位置を記録しています。 関数を処置後に呼び出してステップ実行する コマンドi(see Jumping)も参照してください。

edebugは、標準のスペシャルフォームすべて、 式を引数とするinteractiveフォーム、 無名ラムダ式、他の定義フォームをどのように処置するかわかっています。 edebugは、マクロ呼び出しを引数に持つユーザー定義マクロをどのように 処置すべきかわかりませんから、読者がそれを指示する必要があります。 詳しくは、See Instrumenting Macro Calls

edebugは、あるセッションで初めてコードを処置する場合、 フックedebug-setup-hookを実行してから それにnilを設定します。 これを利用すると、読者が使用するパッケージに対応した edebug用仕様(see Instrumenting Macro Calls)を edebugを使用する場合にのみロードするようにできます。

定義から処置を取り除くには、 処置しないような方法でその定義を単に再評価するだけです。 けっして処置せずにフォームを評価する方法は2つあります。 ファイルをloadするか、 ミニバッファでeval-expressionM-:)を使います。

edebugが処置中に構文エラーを検出すると、 コードのエラー箇所にポイントを置いて、 エラーinvalid-read-syntaxを通知します。

edebugの内側で使える他の評価関数についてはSee Edebug Eval


Node:Edebug Execution Modes, Next:, Previous:Instrumenting, Up:Edebug

edebugの実行モード

edebugには読者がデバッグしているプログラムを実行するための 実行モードが複数あります。 これらをedebugの実行モードと呼びます。 これらをメジャーモードやマイナモードと混同しないでください。 edebugの実行モードは、停止するまでにどの程度edebugが実行を継続するか、 たとえば、各停止位置で停止するのかつぎのブレークポイントまで継続するのか、 また、停止するまでに評価の進行状況をどの程度edebugが表示するのかを 決定します。

通常、あるモードにおいて、 プログラムを継続するコマンドを打つことでedebugの実行モードを指定します。 以下にそれらのコマンドの一覧を示します。 Sを除くすべてのコマンドは、 少なくともある程度プログラムの実行を再開します。

S
停止: プログラムをいっさい実行せずに、 edebugコマンドの入力を待つ(edebug-stop)。
<SPC>
ステップ実行: つぎに出会う停止位置で止まる(edebug-step-mode)。
n
つぎ: 式のうしろでつぎに出会う停止位置で止まる (edebug-next-mode)。 Edebug Miscedebug-forward-sexpも参照。
t
トレース: edebugの各停止位置で1秒間休止する (edebug-trace-mode)。
T
高速トレース: 各停止位置で表示を更新するが休止しない (edebug-Trace-fast-mode)。
g
実行: つぎのブレークポイントまで実行する (edebug-go-mode)。 see Breakpoints
c
継続: 各ブレークポイントで1秒間休止してから継続する (edebug-continue-mode)。
C
高速継続: 各ブレークポイントへポイントを移動するが休止しない (edebug-Continue-fast-mode)。
G
非停止実行: ブレークポイントを無視する (edebug-Go-nonstop-mode)。 Sや編集コマンドを打てば停止できる。

一般に、上記一覧の上にある実行モードほど下にあるものに比べると プログラムをゆっくり実行、つまり、早く停止します。

実行中やトレース中には、edebugコマンドをなにか打てば実行に割り込めます。 edebugはつぎの停止位置でプログラムを止め、 読者が打ったコマンドを実行します。 たとえば、実行中にtを打てば、つぎの停止位置でトレースモードに 切り替わります。 単に実行を停止するにはSを使います。

読者の関数が入力を読み取る場合、実行に割り込むつもりで打った文字を 関数が読み取ってしまうかもしれません。 読者のプログラムがいつ入力するかに注意していれば、 このような意図しない結果を避けることができます。

本節で述べたコマンドを含むキーボードマクロは動作しません。 つまり、プログラムを再開するためにedebugから抜けると キーボードマクロの制御を失ってしまいます。 これを修正するのは簡単ではありません。 また、edebugの外側でキーボードマクロを定義したり実行しても、 edebug内のコマンドにはなんの影響もありません。 これは普通は利点です。 しかし、オプションedebug-continue-kbd-macro (see Edebug Options)も参照してください。

edebugの新たなレベルに入ると、変数edebug-initial-modeの値を 実行モードの初期値とします。 デフォルトでは、これはステップ実行モードを指定します。 処置した関数を1つのコマンドから複数回呼び出すなどして edebugの同一レベルに再度入ることができることに注意してください。


Node:Jumping, Next:, Previous:Edebug Execution Modes, Up:Edebug

ジャンプ

本節で述べるコマンドは、指定した位置に達するまで実行します。 iを除くすべてのものは、停止する場所に一時的なブレークポイントを 設定してから実行モードに移行します。 意図したブレークポイントより先に別のブレークポイントに達しても 実行を停止します。 ブレークポイントについて詳しくはSee Breakpoints

非ローカル脱出は、読者が意図したプログラムの停止すべき 一時的なブレークポイントを迂回するため、 これらのコマンドは非ローカル脱出があると意図したように動作しません。

h
ポイント位置付近の停止位置まで進む(edebug-goto-here)。
f
プログラムの式1つ分先へ進む(edebug-forward-sexp)。
o
囲んでいるS式の終りまでプログラムを実行する。
i
ポイントのあとのフォームから呼ばれる関数やマクロへ進む。

コマンドhは、一時的なブレークポイントを使って、 ポイント位置付近の停止位置まで進みます。 ブレークポイントについて詳しくはSee Breakpoints

コマンドfは、プログラムの式1つ分先へ進みます。 より正確には、C-M-fによる移動箇所へ一時的なブレークポイントを設定し、 プログラムがブレークポイントで停止するような実行モードで実行します。

前置引数nを指定すると、 ポイント位置からn個先のS式に一時的なブレークポイントを設定します。 囲んでいるリストの残り要素数がnより少なければ、 囲んでいる式の末尾で停止します。

C-M-fの移動先はプログラムが実際に停止するであろう箇所です。 これが正しくない場合もあり、たとえば、condでは正しくありません。

コマンドfは、柔軟性のために、 停止位置ではなくポイント位置でforward-sexpを使います。 現在の停止位置から式1つだけ実行したい場合には、 まずwと打ってポイントを停止位置に移動してからfを打ちます。

コマンドoは式から『出る』まで実行します。 ポイントを含むS式の末尾に一時的なブレークポイントを置きます。 このS式が関数定義そのものである場合には、 oは定義の最後のS式の手前まで実行します。 現在この箇所にいた場合には、関数から戻ってから停止します。 いいかえれば、最後のS式のあとに位置していない限り、 このコマンドは現在実行中の関数から抜けません。

コマンドiは、 ポイント位置のあとにあるリストフォームから呼ばれる関数やマクロへ進み、 最初に出会った停止位置で止まります。 そのフォームはこれから評価されるフォームである必要はありません。 しかし、評価されるフォームが関数呼び出しである場合には、 引数を評価するまえにこのコマンドを使うことを覚えておいてください。 さもないとこのコマンドを使う時期が遅すぎます。

コマンドiは、呼び出す関数やマクロが処置されていないと それらを処置します。 これは便利ですが、それらの関数やマクロは、明示的に処置を取り除かない限り、 処置したままになります。


Node:Edebug Misc, Next:, Previous:Jumping, Up:Edebug

edebugのその他のコマンド

edebugの他のコマンドを以下に示します。

?
edebugのヘルプメッセージを表示する(edebug-help)。
C-]
1つまえのレベルのコマンドレベルへ戻る(abort-recursive-edit)。
q
エディタのトップレベルのコマンドループへ戻る(top-level)。 edebugのすべての動作中のレベルを含めて、すべての再帰編集レベルから抜ける。 しかし、フォームunwind-protectcondition-caseで保護した 処置済みのコードがあるとデバッガを再開する。
Q
qと同様であるが保護したコードでも停止しない (top-level-nonstop)。
r
もっとも最近の式の既知の結果をエコー領域に再表示する (edebug-previous-result)。
d
わかりやすいようにedebug自体の関数を除外してバックトレースを表示する (edebug-backtrace)。

edebugのバックトレースバッファでは、 標準のデバッガのようにはデバッガのコマンドを使えない。

実行を継続するとバックトレースバッファは自動的に削除される。

edebugの再帰編集から、edebugを再帰的に活性にするコマンドを起動できます。 edebugが活性であるときにはいつでもqでトップレベルへ戻るか、 C-]で1つの再帰編集レベルを抜けることができます。 保留している評価すべてのバックトレースはdで表示できます。


Node:Breakpoints, Next:, Previous:Edebug Misc, Up:Edebug

ブレークポイント

edebugのステップ実行モードは、つぎの停止位置に達すると実行を停止します。 edebugが実行を止める方法は3つあります。 ブレークポイント、グローバルブレーク条件、ソースのブレークポイントです。

edebugを使用中には、読者がテスト中のプログラムにブレークポイント (breakpoint)、つまり、実行を停止すべき箇所を設定できます。 Using Edebugで定義した任意の停止位置にブレークポイントを設定できます。 ブレークポイントの設定や解除において対象となる停止位置は、 ソースコードバッファのポイント位置かそのあとにある停止位置です。 ブレークポイントに関するedebugコマンドはつぎのとおりです。

b
ポイント位置かそのうしろにある停止位置にブレークポイントを設定する (edebug-set-breakpoint)。 前置引数を指定すると、一時的なブレークポイントになる (そこでプログラムが停止すると解除される)。
u
ポイント位置かそのうしろにある停止位置の(あれば)ブレークポイントを解除する (edebug-unset-breakpoint)。
x condition <RET>
conditionnil以外の値に評価される場合にのみ プログラムを停止する条件付きブレークポイントを設定する (edebug-set-conditional-breakpoint)。 前置引数を指定すると、一時的なブレークポイントになる。
B
現在の定義内にあるつぎのブレークポイントにポイント位置を移動する (edebug-next-breakpoint)。

edebug内では、bでブレークポイントを設定し、 uで解除できます。 まず目的のedegugの停止位置にポイント位置を移動し、 bを打ってその箇所にブレークポイントを設定したり、 uを打ってその箇所のブレークポイントを解除します。 設定されていないブレークポイントを解除しても、なにも起こりません。

定義を再評価したり再処置すると、その中のブレークポイントすべてを解除します。

条件付きブレークポイント(conditional breakpoint)は、 プログラムがこの箇所に達するたびに条件を検査します。 条件を評価中に発生するどんなエラーも無視し、 nilとして扱います。 条件付きブレークポイントを設定するにはxを使い、 条件式はミニバッファで指定します。 すでに条件付きブレークポイントを設定してある停止位置に 条件付きブレークポイントを設定し直すと、 それまでの条件式がミニバッファに入るので編集できます。

ブレークポイントを設定するコマンドに前置引数を指定すると、 条件付き/無条件ブレークポイントを一時的なものにできます。 一時的ブレークポイントでプログラムが停止すると、 そのブレークポイントは自動的に解除されます。

edebugのモードが非停止実行でなければ、 edebugはブレークポイントでつねに停止するか休止します。 非停止実行モードでは、ブレークポイントを完全に無視します。

ブレークポイントの場所を確認するには、コマンドBを使います。 同じ関数内のポイント箇所のうしろにあるブレークポイントか、 後続のものがなければ最初のブレークポイントにポイント位置を移動します。 このコマンドは実行を継続しません。 バッファ内で単にポイントを移動するだけです。


Node:Global Break Condition, Next:, Up:Breakpoints

グローバルブレーク条件

グローバルブレーク条件(global break condition)は、 指定した条件が満たされると、その場所に関わらず、実行を停止させます。 edebugは各停止位置においてグローバルブレーク条件を評価します。 これがnil以外の値であると、 ブレークポイントに達したかのように、 実行モードに依存して実行を停止するか休止します。 条件の評価中にエラーが発生しても実行は停止しません。

条件式はedebug-global-break-conditionに保存されます。 コマンドXで新たな条件式を指定できます (edebug-set-global-break-condition)。

グローバルブレーク条件は、読者のコードのどこでイベントが発生するかを 調べるもっとも簡単な方法ですが、コードの実行速度をかなり遅くします。 ですから、使用しない場合には条件をnilに再設定すべきです。


Node:Source Breakpoints, Previous:Global Break Condition, Up:Breakpoints

ソース上のブレークポイント

定義内のすべてのブレークポイントは、定義を処置し直すたびに失われます。 ブレークポイントを失いたくない場合には、 ソース上のブレークポイント(source breakpoint)を指定できます。 これはソースコード上で関数edebugを呼び出すだけです。 もちろん、条件付けして呼び出せます。 たとえば、関数facにおいて、引数がゼロの場合に停止するには、 以下に示すように最初の行を挿入します。

(defun fac (n)
  (if (= n 0) (edebug))
  (if (< 0 n)
      (* n (fac (1- n)))
    1))

関数facを処置してこの関数を呼び出すと、 edebugの呼び出しはブレークポイントのように動作します。 実行モードに応じて、edebugはその箇所で停止するか休止します。

edebugを呼び出したコードが処置済みでなければ、 この関数はdebugを呼び出します。


Node:Trapping Errors, Next:, Previous:Breakpoints, Up:Edebug

エラーの捕捉

Emacsは、通常、エラーが通知されてもcondition-caseで処理されなかった 場合、エラーメッセージを表示します。 edebugが活性であり処置済みのコードを実行していると、 edebugは処理されなかったエラーすべてに反応します。 この動作をedebug-on-erroredebug-on-quitで カスタマイズできます。 See Edebug Options

edebugがエラーに反応すると、 エラーを起こすまえ出会った最後の停止位置を表示します。 この位置は、実際にエラーを起こした処置してない関数の呼び出し位置である 場合もあります。 未束縛な変数のエラーでは、最後の停止位置は、 当該変数の参照位置からかなり離れている場合があります。 そのような場合には、完全なバックトレースを表示したいでしょう (see Edebug Misc)。

edebugが活性なときにdebug-on-errordebug-on-quitを変更しても、 edebugが不活性になったときにそれらの変更を取り消してしまいます。 さらに、edebugの再帰編集中は、これらの変数はedebugの外側での値に 束縛されます。


Node:Edebug Views, Next:, Previous:Trapping Errors, Up:Edebug

edebugのビュー

これらのedebugのコマンドは、edebugに入るまえのバッファやウィンドウの 状態を調べるものです。 外部ウィンドウ構成は、edebugの外側でのウィンドウの集まりや内容に 関するものです。

v
外部ウィンドウ構成を一時的に見る (edebug-view-outside)。
p
edebugの外側でのカレントバッファと外側でのポイント位置を 一時的に表示する(edebug-bounce-point)。 前置引数nは、かわりに休止秒数を指定する。
w
ソースコードバッファで現在の停止位置にポイント位置を戻す (edebug-where)。

同じバッファを表示している別のウィンドウでこのコマンドを使うと、 それ以後、そのウィンドウに現在の定義が表示されるようになる。

W
edebugが外部ウィンドウ構成を保存/復元するかどうかをトグルする (edebug-toggle-save-windows)。

前置引数を指定すると選択したウィンドウだけの保存/復元をトグルする。 ソースコードバッファを表示していないウィンドウを指定するには、 グローバルキーマップのC-x X Wを使う必要がある。

vで外部ウィンドウ構成を見ることができます。 あるいは、(edebugの外側での)カレントバッファが表示されていなくても pでカレントバッファのポイント位置を見ることができます。 ポイント位置を移動したら、 wでソースコードバッファの停止位置へ戻れます。

外部ウィンドウ構成を保存しないようにWを使うたびに、 edebugは保存しておいた外部ウィンドウ構成を破棄します。 そのため、保存するように戻しても、 (プログラムを続行することで)edebugを抜けると、 現在のウィンドウ構成は変更されません。 しかし、*edebug**edebug-trace*の自動再表示は、 十分なウィンドウが開いてないと、 読者が見たいバッファと衝突するかもしれません。


Node:Edebug Eval, Next:, Previous:Edebug Views, Up:Edebug

評価

edebugの内側では、edebugが動作していないがごとく式を評価できます。 edebugは、式の評価と表示に対して見えないようにします。 edebugが明示的に保存/復元する場合を除いて、 副作用を持つ式の評価も期待どおり動作します。 この処理に関して詳しくはSee The Outside Context

e exp <RET>
edebugの外側の文脈で式expを評価する (edebug-eval-expression)。 つまり、edebugは評価への干渉を最小限にとどめようとする。
M-: exp <RET>
edebug自身の文脈で式expを評価する。
C-x C-e
edebugの外側の文脈でポイント位置のまえの式を評価する (edebug-eval-last-sexp)。

edebugはcl.el(版2.03以降)内の構文 lexical-letmacroletsymbol-macroletで 作成されるレキシカル(テキスト上の)束縛を参照する式の評価を扱えます。


Node:Eval List, Next:, Previous:Edebug Eval, Up:Edebug

評価リストバッファ

*edebug*と呼ばれる評価リストバッファを使って、 式を対話的に評価できます。 さらに、edebugが表示を更新するたびに自動的に評価される 式の評価リストを設定することもできます。

E
評価リストバッファ*edebug*へ切り替える (edebug-visit-eval-list)。

バッファ*edebug*では、以下の特別なコマンドに加えて lisp対話モード (see Lisp Interaction) のコマンドも使えます。

C-j
外側の文脈でポイント位置のまえの式を評価し、 その値をバッファに挿入する (edebug-eval-print-last-sexp)。
C-x C-e
edebugの外側の文脈でポイント位置のまえの式を評価する (edebug-eval-last-sexp)。
C-c C-u
バッファの内容から新たな評価リストを構築する (edebug-update-eval-list)。
C-c C-d
ポイント位置にある評価リストグループを削除する (edebug-delete-eval-item)。
C-c C-w
ソースコードバッファに切り替え現在の停止位置に戻る (edebug-where)。

*scratch*で行うのと同様に、 評価リストウィンドウではC-jC-x C-eで式を評価できますが、 それらはedebugの外側の文脈で評価されます。

実行を継続すると、対話的に入力した式(やその結果)は破棄されますが、 実行を停止するたびに評価される式から成る評価リスト(evaluation list) を設定できます。

これを行うには、評価リストバッファにて、 1つ以上の評価リストグループ(evaluation list group)を書きます。 評価リストグループは、1つ以上のLisp式から成ります。 グループはコメント行で区切ります。

コマンドC-c C-uedebug-update-eval-list)は、 バッファを走査して各グループの最初の式を使って 評価リストを再構築します。 (各グループの2番目の式は計算結果を表示した値とみなす。)

edebugに入るたびに、各式に続けてその現在値をバッファに挿入することで 評価リストを再表示します。 このとき、各式がそれぞれグループになるようにコメント行も挿入します。 したがって、バッファのテキストを変更せずに再度C-c C-uと打つと、 評価リストは実質的には変更されません。

評価リストの評価中にエラーが発生すると、 エラーメッセージを評価結果とみなして文字列で表示します。 したがって、現在の文脈では不正な変数を式に使っても 読者のデバッグを遮ることはありません。

評価リストウィンドウに数個の式を追加したときのようすを以下に示します。

(current-buffer)
#<buffer *scratch*>
;---------------------------------------------------------------
(selected-window)
#<window 16 on *scratch*>
;---------------------------------------------------------------
(point)
196
;---------------------------------------------------------------
bad-var
"Symbol's value as variable is void: bad-var"
;---------------------------------------------------------------
(recursion-depth)
0
;---------------------------------------------------------------
this-command
eval-last-sexp
;---------------------------------------------------------------

グループを削除するには、そこへポイントを移動してC-c C-dと打ちます。 あるいは、グループのテキストを単に削除してからC-c C-uで 評価リストを更新します。 評価リストに新たに式を追加するには、 適切な位置に式を挿入し、新たなコメント行を挿入します。 (コメント行にマイナス記号を挿入する必要はない。 コメントの内容は関係ない。) そして、C-c C-uと打ちます

*edebug*を選択したあとは、 C-c C-wでソースコードバッファへ戻れます。 読者が実行を継続するとバッファ*edebug*は削除され、 つぎに必要なときに再度作成されます。


Node:Printing in Edebug, Next:, Previous:Eval List, Up:Edebug

edebugでの出力

読者のプログラムの式が循環したリスト構造を含む値を作り出す場合、 edebugがそれを出力しようとするとエラーになります。

循環構造を扱う1つの方法は、出力を切り詰めるために print-lengthprint-levelを設定することです。 edebugが読者のためにこれを行います。 それらがnilであると、 edebugはprint-lengthprint-levelを50に束縛します。 (実際は、edebugが使う値は e-debug-print-lengthe-debug-print-levelが指定する。) See Output Variables

edebug-print-length User Option
nil以外であると、edebugが結果を出力するときには、 これをprint-lengthに束縛する。 デフォルト値は50

edebug-print-level User Option
nil以外であると、edebugが結果を出力するときには、 これをprint-levelに束縛する。 デフォルト値は50

パッケージcust-printを使えば、 循環構造や要素を共有する構造をより的確に出力することもできます。

cust-printをロードしてedebugでのみこの特別な出力を使うようにするには、 単にコマンドM-x edebug-install-custom-printを使うだけです。 標準の出力関数に戻すには、M-x edebug-uninstall-custom-printを使います。

循環構造を作るコードの例を示します。

(setq a '(x y))
(setcar a a)

特別な出力ではこれをResult: #1=(#1# y)と出力します。 #1=の記法は、これに続く構造に1というラベルを付けます。 また、#1#の記法はすでにラベル付けした構造を参照します。 この記法は、リストやベクトルの任意の共有された要素に使われます。

edebug-print-circle User Option
nil以外であると、edebugが結果を出力するときには、 これをprint-circleに束縛する。 デフォルト値はnil

他のプログラムでもこの特別な出力を使えます。 詳しくは、cust-print.elを参照してください。


Node:Trace Buffer, Next:, Previous:Printing in Edebug, Up:Edebug

トレースバッファ

edebugは、実行トレースを*edebug-trace*というバッファに保存することで それらを記録できます。 これは、関数名とそれらの引数、戻り値から成る 関数呼び出しとその戻りの記録です。 トレース記録を有効にするには、 edebug-tracenil以外の値を設定します。

トレースバッファを作成することとトレース実行モードとは 同じではありません(see Edebug Execution Modes)。

トレース記録を有効にしていると、 各関数へ入るときと出るときに、トレースバッファに行が追加されます。 関数へ入るときの記録は、::::{に関数名と引数値が続きます。 関数から出るときの記録は、::::}に関数名とその結果が続きます。

入るときの:の個数は、再帰の深さを表します。 関数呼び出しの対応する開始や対応する終了を探すために トレースバッファでは中括弧を使えます。

関数edebug-print-trace-beforeedebug-print-trace-afterを 再定義すれば、関数へ入ったときと出るときのトレース記録をカスタマイズできます。

edebug-tracing string body... Macro
このマクロはフォームbodyの周りにトレース情報を追加する。 引数stringは、トレースバッファに入れるテキストを指定する。 すべての引数を評価する。 edebug-tracingbodyの最後のフォームの値を返す。

edebug-trace format-string &rest format-args Function
この関数はトレースバッファにテキストを挿入する。 テキストは(apply 'format format-string format-args)で 計算する。 区切りとして改行も挿入する。

edebug-tracingedebug-traceは、 edebugが活性でない場合であっても呼ばれるとトレースバッファに行を挿入します。 トレースバッファにテキストを挿入するとき、 挿入した最後の行が見えるようにウィンドウをスクロールします。


Node:Coverage Testing, Next:, Previous:Trace Buffer, Up:Edebug

カバレッジテスト

edebugでは、初歩的なカバレッジテストや実行頻度を表示できます。

カバレッジテストでは、各式の結果を以前の結果と比較します。 現在のEmacsセッションでカバレッジテストを始めて以降、 プログラムの各フォームが異なる2つの値を返せば、 当該フォームを『カバーした』とみなします。 したがって、読者のプログラムについてカバレッジテストを行うには、 さまざまな条件でそれを実行して正しく動作しているか注意します。 読者が各フォームが異なる2つの値を返すように試行し終れば、 edebugはそのように通知します。

カバレッジテストは実行速度を遅くするので、 edebug-test-coveragenil以外の場合にのみテストします。 すべての処置済み関数の実行に関する頻度数計測は、 非停止実行モードであってもカバレッジテストのオン/オフに関わらず行います。

ある定義に関するカバレッジテストと頻度数計測を表示するには M-x edebug-display-freq-countを使います。

edebug-display-freq-count コマンド
このコマンドは、現在の定義の各行について頻度数データを表示する。

頻度数は、コードの各行のあとにコメント行として表示され、 コマンドundoでそれらのコメント行の挿入をアンドゥできる。 頻度数は、式のまえの(や式のうしろの)の直下、 あるいは、変数の最後の文字に表示される。 表示を簡素にするために、頻度数が同じ行のまえのほうの式の頻度数と同じであると 表示しない。

式の頻度数に続く文字=は、 その式を評価するたびに同じ値を返したことを意味する。 いいかえれば、カバレッジテストとしては、 その式はまだ『カバーして』いないことになる。

ある定義に関する頻度数計測とカバレッジデータをクリアするには、 eval-defunで単に再処置すればよい。

たとえば、edebug-test-coveragetとし、 ソース上のブレークポイントを設定して(fac 5)を評価すると、 ブレークポイントに達したときの頻度数データはつぎのようになります。

(defun fac (n)
  (if (= n 0) (edebug))
;#6           1      0 =5
  (if (< 0 n)
;#5         =
      (* n (fac (1- n)))
;#    5               0
    1))
;#   0

コメント行は、facが6回呼ばれたことを表します。 最初のif文は、5回とも同じ結果を返したのです。 2番目のifについても同じです。 facの再帰呼び出しは1度も戻っていません。


Node:The Outside Context, Next:, Previous:Coverage Testing, Up:Edebug

外側の文脈

edebugは、読者がデバッグ中のプログラムに対しては透過であるように努めますが、 完全にうまくいくとは限りません。 また、eで読者が式を評価するときや評価リストバッファでも、 外側の文脈を一時的に復元して透過であるように努めます。 本節では、edebugが復元する文脈について正確に説明し、 edebugが透過にならない場合についても説明します。


Node:Checking Whether to Stop, Next:, Up:The Outside Context

停止すべきかどうかの検査

edebugに入ると、トレース情報を作るのかプログラムを停止するのかを 決定するまえであってもある種のデータを保存/復元する必要が つねにあります。


Node:Edebug Display Update, Next:, Previous:Checking Whether to Stop, Up:The Outside Context

edebugの表示の更新

edebugが(トレースモードなどで)なにかを表示する必要があると、 edebugの『外側』の現在のウィンドウ構成を保存します (see Window Configurations)。 (プログラムを続行して)edebugを抜けるときには、 以前のウィンドウ構成を復元します

Emacsは休止するときにのみ表示を更新します。 通常、プログラムを続行しても、休止したり入力を読むことなく ブレークポイントやステップ実行によりedebugへ戻ります。 そのような場合、Emacsには(edebugの)『外側』のようすを再表示する 機会が与えられません。 見かけ上、ウィンドウの表示は直前にedebugが活性であったときと同じになります。

なにかを表示するためにedebugに入っても以下のデータを保存/復元しますが、 エラーや中断が起こると、故意に復元しないものもあります。


Node:Edebug Recursive Edit, Previous:Edebug Display Update, Up:The Outside Context

edebugの再帰編集

edebugに入ってユーザーコマンドを読み取るとき、 以下のデータを保存し(のちに復元し)ます。


Node:Instrumenting Macro Calls, Next:, Previous:The Outside Context, Up:Edebug

マクロ呼び出しの処置

edebugがLispマクロを呼び出す式を処置するとき、 それを正しく行うにはマクロに関する余分な情報を必要とします。 マクロ呼び出しのどの部分式が評価されるフォームであるかを 明確に判定する方法がないからです。 (マクロ本体で明示的に評価されるか、 結果の展開形が評価されるときか、あるいは、さらにあと)

したがって、edebugが出会う各マクロについて、 当該マクロの呼び出し形式を記述するedebug用仕様を定義する必要があります。 これには、def-edebug-specを使います。

def-edebug-spec macro specification マクロ
マクロmacroの呼び出しのどの式が評価されるかを指定する。 単純なマクロでは、specificationは マクロ定義の仮引数リストに似ているが、 その指定はマクロ引数よりも汎用性がある。

引数macroはマクロ名だけでなく任意のシンボルでよい。

例題マクロfor(see Argument Evaluation)の edebug用仕様の等価な定義例2つを示します。

(def-edebug-spec for
  (symbolp "from" form "to" form "do" &rest form))

(def-edebug-spec for
  (symbolp ['from form] ['to form] ['do body]))

specificationに指定するものとその引数の処理方法は次表のとおりです。

t
すべての引数を評価するように処置する。
0
引数はいっさい処置しない。
シンボル
edebug用仕様を持つシンボルをかわりに使う。 この間接参照は別の種類の仕様を得るまで繰り返す。 これにより、別のマクロから仕様を継承できる。
リスト
リストの各要素は、呼び出しフォームの引数の型を記述する。 仕様リストの各要素については次節で述べる。


Node:Specification List, Next:, Up:Instrumenting Macro Calls

仕様リスト

マクロ呼び出しの引数のあるものは評価し別のものは評価しない場合には、 edebug用仕様に仕様リスト(specification list)が必要になります。 複数の引数に一致する仕様リストの要素もありますが、 後続の要素の処理を修飾する要素もあります。 後者は仕様キーワード(specification keyword)と呼ばれ、 (&optionalのように)&で始まるシンボルです。

仕様リストには、それ自体がリストである引数に一致する部分リストや グループ化に使うベクトルを含んでもかまいません。 部分リストやグループは仕様リストを階層に分けます。 仕様キーワードはそれらを含む部分リストやグループの残りに適用されます。

仕様リストに選択肢や繰り返しが含まれる場合、 実際のマクロ呼び出しに一致させるにはバックトラックが必要な場合もあります。 詳しくはSee Backtracking

edebug用仕様では、正規表現による一致と文脈自由文法の構文を使えます。 対応した括弧に囲まれた部分リスト、フォームの再帰的処理、 間接仕様による再帰です。

仕様リストの要素に指定できるものとそれらの意味を以下に示します。

sexp
処置しない評価しない1つのLispオブジェクト。
form
処置した評価する1つの式。
place
Common Lispのsetf構文のように値を格納する場所。
body
&rest formの省略形。 以下の&restを参照。
function-form
関数フォーム。 クォートした関数シンボル、クォートしたラムダ式、 あるいは、(関数シンボルやラムダ式に評価される)フォーム。 これは、ラムダ式である引数が、 functionではなくquoteでクォートされるときに有用である。 というのは、ラムダ式の本体をいずれかの方法で処置するからである。
lambda-expr
クォートしていないラムダ式。
&optional
この仕様リスト内の後続の要素すべては省略可能。 一致しないと、edebugはただちにこのレベルの一致を止める。

数個の省略可能な要素に省略不可な要素を続けるには、 [&optional specs...]を使う。 数個の要素がすべて一致するかまったく一致しないことを指定するには、 &optional [specs...]を使う。 以下のdefunの例を参照。

&rest
この仕様リスト内の後続の要素すべてを0回以上繰り返す。 最後の繰り返しでは、仕様リストの要素すべてに一致するまえに 式を使い尽くしても問題にはならない。

数個の要素のみを繰り返すには[&rest specs...]を使う。 各繰り返しですべてが一致するような数個の要素を指定するには、 &rest [specs...]を使う。

&or
仕様リスト内の後続の各リストは選択肢を表す。 選択肢の1つに一致しなければ、仕様&orは失敗。

&orに続く各要素は1つの選択肢を表す。 複数の要素を1つの選択肢としてグループにまとめるには、 それらを[...]で囲む。

&not
&orを使ったかように後続の要素を選択肢として一致させるが、 どれかが一致すると仕様は失敗。 どれにも一致しなければ、仕様&notは成功。
&define
仕様は定義フォームに対するものであることを表す。 定義フォームそのものは処置しない (つまり、edbugは定義フォームの前後で停止しない)が、 この内側にあるフォームは典型的には処置される。 キーワード&defineはリスト仕様の最初の要素である必要がある。
nil
現在の引数リストのレベルにおいて一致する引数がなければ成功する。 さもなければ失敗。 部分リスト仕様と以下のバッククォートの例を参照。
gate
いかなる引数とも一致しないが、このゲートを通ると、 このレベルの仕様の残りの部分と一致を調べる際には バックトラックを禁止する。 これは主により詳しい構文エラーメッセージを生成するために使う。 詳しくはBacktrackingを参照。 例については以下のletを参照。
その他のシンボル
仕様リストのその他のシンボルは述語であるか間接仕様である。

シンボルにedebug用仕様があれば、 この間接仕様は、シンボルのかわりに使われる仕様リストであるか、 引数を処理するために呼び出される関数であること。 仕様は、マクロ向けにdef-edebug-specで定義した仕様であってもよい。 以下のdefunの例を参照。

さもなければ、シンボルは述語であること。 述語は引数で呼び出され、述語がnilを返すと仕様は失敗する。 いずれの場合でも、当該引数は処置されない。

適当な述語には、symbolpintegerpstringpvectorpatomがある。

[elements...]
要素のベクトルは要素群を単一のグループ仕様にまとめる。 この意味はベクトルの意味とは関係ない。
"string"
引数はstringという名前のシンボルであること。 この仕様は、symbolの名前がstringである クォートとしたシンボル'symbolと等価であるが、 文字列のほうが望ましい。
(vector elements...)
引数は、仕様内のelementsに一致するものを要素とするベクトルであること。 以下のバッククォートの例を参照。
(elements...)
その他のリストは部分リスト仕様であり、 引数は仕様elementsに一致するものを要素とするリストであること。

部分リスト仕様はドット対リストでもよく、その場合、 対応するリスト引数はドット対リストである。 あるいは、ドット対リスト仕様の最後のCDRは ((spec . [(more specs...)])などの グループや間接仕様を介した) 別の部分リスト仕様であってもよいが、 それらの要素はドット対ではないリスト引数に一致する。 これは、以下のバッククォートの例のような再帰仕様に有用である。 このような再帰を終らせるうえの仕様nilも参照。

(specs . nil)(specs . (sublist-elements...))のような部分リスト仕様は (specs sublist-elements...)と等価であることに注意。

&defineのうしろに追加できる仕様の一覧を以下に示します。 以下のdefunの例を参照してください。

name
引数はシンボルであり、定義フォームの名前である。

定義フォームには単一の名前フィールドがある必要はなく、 複数の名前フィールドを持っていてもよい。

:name
この構造は引数には実際には一致しない。 :nameに続く要素はシンボルであること。 定義に対する追加の名前要素として使う。 定義の名前に一意で静的な要素を追加するために使う。 複数あってもよい。
arg
引数はシンボルであり、定義フォームの引数の名前である。 しかし、ラムダリストキーワード(&で始まるシンボル)は許されない。
lambda-list
ラムダリスト、すなわち、ラムダ式の引数リストに一致する。
def-body
引数は、定義内のコード本体である。 これは、上に述べたbodyに似ているが、 定義本体は定義に関連した情報を調べる異なるedebug呼び出しで処置する必要がある。 定義内のフォームの最上位レベルのリストにはdef-bodyを使う。
def-form
引数は、定義内の単一の最上位レベルのフォームである。 これはdef-bodyに似ているが、 フォームのリストではなく単一のフォームに一致するものに使う。 特別な場合として、def-formは フォームを実行したときにトレース情報を出力しないことを意味する。 以下のinteractiveの例を参照。


Node:Backtracking, Next:, Previous:Specification List, Up:Instrumenting Macro Calls

仕様内でのバックトラック

仕様の一致がある箇所で失敗しても、 必ずしも構文エラーが通知されるとは限りません。 そのかわりに、選択肢すべてを試し尽くすまでバックトラックします。 最終的に、引数リストの各要素は仕様内のいずれかの要素に一致する必要があり、 仕様内の各必須要素はいずれかの引数に一致する必要があります。

構文エラーを検出しても、より高いレベルの選択肢を使い切るまでは報告されず、 実際のエラー箇所から離れた箇所にポイントが置かれます。 しかし、エラー発生時にバックトラックが禁止されていれば、 ただちにエラーが報告されます。 さまざまな状況でバックトラックが自動的に再許可されることに注意してください。 &optional&rest&orで新たに選択肢が指定されたり、 部分リストやグループや間接仕様を処理し始めると、 自動的に再許可されます。 バックトラックの許可/禁止の効果は、 現在処理しているレベルやそれより低いレベルに限定されます。

任意のフォーム仕様(つまり、formbodydef-formdef-body)の一致処理中には、バックトラックを禁止します。 これらの仕様は任意のフォームに一致するので、 エラーはより上のレベルではなくフォーム自身にあるはずです。

また、クォートしたシンボルや文字列の仕様に一致すると バックトラックを禁止します。 というのは、通常、これは構造を認識したことを意味するからです。 しかし、すべてが同一シンボルで始まる選択肢を指定する場合には、 ["foo" &or [first case] [second case] ...]のように、 そのシンボルを選択肢から括り出せばバックトラックするようにできます。

多くの場合では、バックトラックを自動的に禁止するこれらの2つの方法で十分ですが、 仕様gateを使ってバックトラックを明示的に禁止すると有用な場合もあります。 上位の選択肢が適用できないとわかっている場合に有用です。 仕様letの例を参照してください。


Node:Specification Examples, Previous:Backtracking, Up:Instrumenting Macro Calls

仕様の例

以下の例を参考にするとedebug用仕様を理解しやすいでしょう。

スペシャルフォームletには束縛と本体の並びがあります。 各束縛は、シンボル、あるいは、シンボルと省略可能な式から成る部分リストです。 以下のedebug用仕様では、部分リストの内側にあるgateで、 部分リストを一度みつけるとバックトラックを禁止していることに 注意してください。

(def-edebug-spec let
  ((&rest
    &or symbolp (gate symbolp &optional form))
   body))

edebugは、defundefmacro、 および、対応する引数リストと仕様interactiveに対しては、 以下のedebug用仕様を使います。 式の引数は実際には関数本体の外側で評価されるので、 対話宣言フォームを特別扱いする必要があります。

(def-edebug-spec defmacro defun) ; 仕様defunの間接参照
(def-edebug-spec defun
  (&define name lambda-list
           [&optional stringp]   ; あれば、説明文字列に一致する
           [&optional ("interactive" interactive)]
           def-body))

(def-edebug-spec lambda-list
  (([&rest arg]
    [&optional ["&optional" arg &rest arg]]
    &optional ["&rest" arg]
    )))

(def-edebug-spec interactive
  (&optional &or stringp def-form))    ; def-formを参照

以下のバッククォートに対する仕様は、 ドット対リストの一致の仕方と再帰を終らせるnilの使い方を示します。 また、ベクトルの要素の一致の仕方も示します。 (edebugが実際に定義している仕様では、 失敗の可能性がある非常に深い再帰をもたらすためドット対リストを扱わない。)

(def-edebug-spec ` (backquote-form))   ; わかりやすいように別名を付ける

(def-edebug-spec backquote-form
  (&or ([&or "," ",@"] &or ("quote" backquote-form) form)
       (backquote-form . [&or nil backquote-form])
       (vector &rest backquote-form)
       sexp))


Node:Edebug Options, Previous:Instrumenting Macro Calls, Up:Edebug

edebugのオプション

以下のオプションはedebugの動作に影響します。

edebug-setup-hook User Option
edebugを使うまえに呼び出す関数群。 新たな値に設定されるたびに、edebugはこれらの関数を呼び出し、 そのあとでedebug-setup-hooknilに再設定する。 これを用いて、edebugを使用する場合にのみ、 使用するパッケージに対応するedebug用仕様をロードできる。 see Instrumenting

edebug-all-defs User Option
これがnil以外であると、 defundefmacroのような定義フォームを普通に評価すると、 edebug用にそれらを処置する。 これは、eval-defuneval-regioneval-buffereval-current-bufferにも適用される。

このオプションの値をトグルするにはコマンドM-x edebug-all-defsを使う。 see Instrumenting

edebug-all-forms User Option
これがcodenil以外であると、コマンドeval-defuneval-regioneval-buffereval-current-bufferは、 定義しないフォームの場合であってもすべてのフォームを処置する。 これは、ロードやミニバッファでの評価には適用されない。

このオプションの値をトグルするにはコマンドM-x edebug-all-formsを使う。 see Instrumenting

edebug-save-windows User Option
これがnil以外であると、edebugはウィンドウ構成を保存/復元する。 これには時間がかかるので、読者のプログラムがウィンドウ構成に 依存しないのならば、この変数はnilに設定しておくほうがよい。

値がリストであると、リスト内のウィンドウのみを保存/復元する。

edebugのコマンドWを使ってこの変数を対話的に変更できる。 see Edebug Display Update

edebug-save-displayed-buffer-points User Option
これがnil以外であると、edebugは表示されているすべてのバッファの ポイントを保存/復元する。

選択していないウィンドウに表示されたバッファのポイントを変更する コードをデバッグ中には、別のバッファのポイントを保存/復元する必要がある。 edebugやユーザーが当該ウィンドウを選択すると、 そのバッファのポイントはウィンドウのポイント位置に移動する。

すべてのバッファでポイントを保存/復元するには 各ウィンドウを2度選択する必要があるため手間がかかる。 そのため、必要な場合にのみこの機能を有効にする。 see Edebug Display Update

edebug-initial-mode User Option
この変数がnil以外であれば、 edebugが初めて動作するときの初期の動作モードを指定する。 可能な値は、 stepnextgoGo-nonstop, traceTrace-fastcontinueContinue-fast

デフォルト値はstep。 see Edebug Execution Modes

edebug-trace User Option
nil以外であると、関数へ入るときと出るときのトレースを表示することを 意味する。 トレース出力は、*edebug-trace*という名前のバッファに、 関数へ入るときと出るときを各行に再帰の深さで字下げして表示する。

デフォルト値はnilTrace Bufferedebug-tracingも参照。

edebug-test-coverage User Option
nil以外であれば、edebugはデバッグ対象のすべての式のカバレッジ テストを行う。 see Coverage Testing

edebug-continue-kbd-macro User Option
nil以外であれば、 edebugの外側で実行するキーボードマクロを定義したり実行する。 デバッグしないので注意してこのオプションを使うこと。

edebug-on-error User Option
debug-on-errorの以前の値がnilであると、 edebugはdebug-on-errorにこの値を束縛する。 see Trapping Errors

edebug-on-quit User Option
debug-on-quitの以前の値がnilであると、 edebugはdebug-on-quitにこの値を束縛する。 see Trapping Errors

edebugが動作中にedebug-on-erroredebug-on-quitの値を 変更しても、新たなコマンドでedebugをつぎに起動するまでは これらの値は使用されない。

edebug-global-break-condition User Option
nil以外であると、各停止位置で検査される式である。 結果がnil以外であるとブレークする。 エラーは無視する。 see Global Break Condition


Node:Syntax Errors, Next:, Previous:Edebug, Up:Debugging

不正なLisp構文のデバッグ

Lispリーダは不正な構文を報告しますが、どこに問題があるかは報告できません。 たとえば、式を評価中のエラー『End of file during parsing』 (構文解析中にファイルの終り)は、開き括弧(あるいは開き角括弧)が 多すぎることを表します。 Lispリーダは括弧が対応していないことをファイルの末尾で検出しますが、 どこに閉じ括弧があるべきかは判断できません。 同様に、『Invalid read syntax: ")"』(不正な構文:")")は 閉じ括弧が多すぎるか開き括弧が足りないことを表しますが、 どこに括弧が足りないかは判断できません。 それでは、どこを変更すべきかどのように調べるのでしょう?

問題が単純な括弧の非対応でなければ、 各関数定義の先頭でC-M-eを試し、 関数定義の末尾に移動するかどうかをみるのは有用な技法です。 正しく移動しなければ、その関数に問題があります。

Lispによくある構文エラーは括弧の非対応なので、 これらの場面について詳しい助言を述べておきます。 (さらに、対応括弧表示モードをオンにしてポイントを移動すると非対応を 探しやすい。)


Node:Excess Open, Next:, Up:Syntax Errors

開き括弧の過剰

最初の手順は、括弧が対応していない関数定義を探すことです。 開き括弧が過剰であれば、ファイルの末尾に閉じ括弧を挿入し C-M-bbackward-sexp)を打ちます。 こうすると、括弧が対応していない関数定義の先頭へ移動します。 (そうしたら、C-<SPC> C-_ C-u C-<SPC>と打って、 当該箇所にマークを設定してから閉じ括弧の挿入を取り消し、 最終的にマークへ戻る。)

つぎの手順は、なにが悪いか正確に判断することです。 プログラムを調べる以外にこれを確実に行う方法はありませんが、 しばしば、既存の字下げが括弧のありかたを予想する鍵になります。 これを利用するもっとも簡単な方法はC-M-qで字下げし直し、 どのようになるか見ることです。 まだやらないでください! まず読み進んてください。

これを行うまえに、関数定義に充分な数の閉じ括弧があることを確認してください。 さもないと、C-M-qがエラーになったり、 ファイルの末尾までを字下げし直してしまいます。 ですから、関数定義の末尾へ移動して閉じ括弧を挿入しておきます。 C-M-eを使って移動しないでください。 というのは、関数定義の括弧の対応が取れていないと失敗するからです。

関数定義の先頭へ移動してC-M-qを打ちます。 通常、ある場所から関数の末尾までの行が右へずれます。 その場所の近くで、閉じ括弧が足りなかったり開き括弧が多すぎるのです。 (しかし、これが正しいと仮定してはならない。 コードを調べて確認すること。) 不具合箇所がみつかったならば、 意図した括弧に対しては古い字下げが適しているでしょうから C-_C-M-qをアンドゥします。

問題を解決できたと思ったら、再度C-M-qを使います。 古い字下げが意図した括弧の入れ子に対応していて、 必要な括弧を挿入できているならば、 C-M-qはなにも変えないはずです。


Node:Excess Close, Previous:Excess Open, Up:Syntax Errors

閉じ括弧の過剰

過剰な閉じ括弧に対処するには、まず、ファイルの先頭に開き括弧を挿入し、 その括弧のまえでC-M-fを打って、 括弧が対応していない関数定義の末尾を探します。 (そして、C-<SPC> C-_ C-u C-<SPC>と打って、 当該箇所にマークを設定して開き括弧の挿入をアンドゥし、 最終的にマークへ戻る。)

その関数定義の先頭でC-M-fと打って、 実際に対応している閉じ括弧を探します。 これにより、関数定義が終るべき場所より手前の箇所に移動するはずです。 この付近に余分な閉じ括弧がみつかることもあるでしょう。

その場所に問題がなければ、つぎにすべきことは、 関数定義の先頭でC-M-qと打つことです。 ある範囲の行が左にずれるでしょう。 もしそうならば、開き括弧が足りないか余分な閉じ括弧は、 そのような行の先頭付近にあるでしょう。 (しかし、これが正しいと仮定してはならない。 コードを調べて確認すること。) 不具合箇所がみつかったならば、 意図した括弧に対しては古い字下げが適しているでしょうから C-_C-M-qをアンドゥします。

問題を解決できたと思ったら、再度C-M-qを使います。 古い字下げが意図した括弧の入れ子に対応していて、 必要な括弧を挿入できているならば、 C-M-qはなにも変えないはずです。


Node:Compilation Errors, Previous:Syntax Errors, Up:Debugging

コンパイル時の問題のデバッグ

バイトコンパイル時にエラーが発生したときは、 通常、読者がコンパイルしているプログラムの不正な構文に原因があります。 コンパイラはバッファ*Compile-Log*に適切なエラーメッセージを 表示してから停止します。 メッセージにはエラーとなった関数の名前があったりなかったりします。 いずれにしても、つぎのようにしてファイルのどこでエラーが生じたかを調べます。

まず、バッファ *Compiler Input*に切り替えます。 (バッファ名が空白で始まり、そのため、 M-x list-buffersでは表示されないことに注意。) このバッファにはコンパイルしたプログラムが入っていて、 ポイント位置はバイトコンパイラがどこまで読み取ったかを表します。

エラーの原因が不正なLisp構文であるならば、 ポイント位置が不正構文を検出した箇所を正確に表します。 エラー原因が近くにあるとは限りません! エラーを探すために前節の方法を使ってください。

正しく読み取ったフォームのコンパイル中にエラーを検出したときには、 ポイントはそのフォームの末尾に位置しています。 この場合、この方法ではエラー箇所を正確に判別できませんが、 どの関数を確認すべきかを示しています。


Node:Read and Print, Next:, Previous:Debugging, Up:Top

Lispオブジェクトの読み取りと表示

表示(printing)とは Lispオブジェクトをテキスト表現へ変換する操作であり、 読み取り(reading)は逆の変換操作です。 これには、Lisp Data Typesで述べた表示表現と入力構文を用います。

本章では、読み取りや表示を行うLisp関数について述べます。 また、(読み取るときに)テキストをどこから得たり、 (表示するときに)どこへ出すかを指定する ストリーム(stream)についても述べます。


Node:Streams Intro, Next:, Up:Read and Print

読み取りと表示の概要

Lispオブジェクトの読み取りとは、 テキスト表現のLisp式を解析して対応するLispオブジェクトを生成することを 意味します。 これにより、プログラムはLispコードのファイルからLispへ取り込まれます。 テキストをオブジェクトの入力構文(read syntax)と呼びます。 たとえば、テキスト(a . 5)は、 CARaでありCDRが数5であるコンスセルの入力構文です。

Lispオブジェクトの表示とは、 オブジェクトを表現するテキストを生成することを意味します。 つまり、オブジェクトをその表示表現 (see Printed Representation)に変換します。 上に述べたコンスセルを表示するとテキスト(a . 5)を生成します。

読み取りと表示は、多かれ少なかれ、逆操作です。 与えられたテキスト断片を読み取ることで得られたオブジェクトを表示すると、 しばしば、同じテキストを生成します。 オブジェクトを表示することによって得られたテキストを読み取ると、 通常、似たようなオブジェクトを生成します。 たとえば、シンボルfooを表示するとテキストfooを生成し、 そのテキストを読み取るとシンボルfooが返されます。 要素がabであるリストを表示すると テキスト(a b)を生成し、 そのテキストを読み取ると 要素がabである(もとと同じではないが)リストを生成します。

しかし、これら2つの操作は厳密には逆操作ではありません。 3種類の例外があります。


Node:Input Streams, Next:, Previous:Streams Intro, Up:Read and Print

入力ストリーム

テキストを読み取るほとんどのLisp関数は、 ストリーム(stream)を引数として受け付けます。 入力ストリームは、読み取るべきテキストの文字をどこからどのように得るのかを 指定します。 入力ストリームとして使える型は以下のとおりです。

buffer
入力文字はバッファbufferのポイント直後の文字から読み取られる。 1文字読むごとにポイントを進める。
marker
入力文字は、マーカmarkerがあるバッファの マーカ直後の文字から読み取られる。 1文字読むごとにマーカ位置を進める。 ストリームがマーカであるときには、バッファのポイント位置は影響しない。
string
入力文字は文字列stringの先頭文字から必要な文字数だけ読み取られる。
function
入力文字は関数functionが生成する。 この関数は2種類の呼び出し方を扱える必要がある。
t
ストリームとしてtを使うと、ミニバッファから読み取ることを意味する。 実際には、ミニバッファを表示しユーザーが指定したテキストから成る文字列を作り、 それを入力ストリームとして使う。
nil
入力ストリームとしてnilを指定すると、 standard-inputの値をかわりに使うことを意味する。 その値はデフォルト入力ストリームであり、 nil以外の入力ストリームであること。
symbol
入力ストリームとしてのシンボルは、 そのシンボルの(あれば)関数定義と等価である。

バッファであるストリームからの読み取りの例を 読み取り前後のポイント位置を含めて示します。

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

(read (get-buffer "foo"))
     => is
(read (get-buffer "foo"))
     => the

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

最初の読み取りでは空白を読み飛ばしていることに注意してください。 読み取りでは、意味あるテキストのまえにある白文字はいくつでも読み飛ばします。

つぎは、マーカをストリームとして読み取る例です。 マーカの初期位置は下に示したバッファの先頭にあります。 読み取った値はシンボルThisです。

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

(setq m (set-marker (make-marker) 1 (get-buffer "foo")))
     => #<marker at 1 in foo>
(read m)
     => This
m
     => #<marker at 5 in foo>   ;; 最初の空白の直前

つぎは文字列の内容から読み取ります。

(read "(When in) the course")
     => (When in)

以下の例は、ミニバッファから読み取ります。 プロンプトはLisp expression: です。 (ストリームtから読むとつねにこのプロンプトが使われる。) ユーザーの入力はプロンプトに続けて示してあります。

(read t)
     => 23
---------- Buffer: Minibuffer ----------
Lisp expression: 23 <RET>
---------- Buffer: Minibuffer ----------

最後は、useless-streamという名前の関数をストリームにした例です。 このストリームを使うまえに、 変数useless-listを文字のリストで初期化します。 そうすると、関数useless-streamを呼び出すたびに リスト内のつぎの文字を返すか、 リストの先頭に追加して文字を読み戻します。

(setq useless-list (append "XY()" nil))
     => (88 89 40 41)

(defun useless-stream (&optional unread)
  (if unread
      (setq useless-list (cons unread useless-list))
    (prog1 (car useless-list)
           (setq useless-list (cdr useless-list)))))
     => useless-stream

つぎのようにしてストリームを使って読み取ります。

(read 'useless-stream)
     => XY

useless-list
     => (40 41)

リストには開き括弧と閉じ括弧が残っていることに注意してください。 Lispリーダが開き括弧に出会うとこれで入力を終えると決定し、 それを読み戻すのです。 この時点で読み取りを試みると、 ()を読み取ってnilを返します。

get-file-char Function
この関数は、関数loadで開いた入力ファイルから読み取るための 入力ストリームとして内部的に使われる。 読者はこの関数を使ってはならない。


Node:Input Functions, Next:, Previous:Input Streams, Up:Read and Print

入力関数

本節では読み取りに関係するLisp関数や変数について述べます。

以下の関数では、streamは入力ストリーム(前節参照)を表します。 streamnilであったり省略すると、 standard-inputの値をデフォルトにします。

読み取り中に閉じていないリストやベクトル、文字列に出会うと、 エラーend-of-fileを通知します。

read &optional stream Function
この関数はstreamから1つのLisp式のテキスト表現を読み取り、 それをLispオブジェクトとして返す。 これは基本的なLisp入力関数である。

read-from-string string &optional start end Function
この関数はstringのテキストから先頭のLisp式のテキスト表現を読み取る。 読み取った式をCAR、文字列に残っているつぎの文字 (つまり読み取っていない最初の文字)の位置を表す整数をCDR とするコンスセルを返す。

startが指定してあると、文字列のstartで添字付け (先頭文字の添字は0)されるところから読み始める。 endを指定すると、その添字位置の直前で読み取りを終らせ、 文字列には残りの文字がないかのように扱う。

例:

(read-from-string "(setq x 55) (setq y 5)")
     => ((setq x 55) . 11)
(read-from-string "\"A short string\"")
     => ("A short string" . 16)

;; 最初の文字から読み始める
(read-from-string "(list 112)" 0)
     => ((list 112) . 10)
;; 2番目の文字から読み始める
(read-from-string "(list 112)" 1)
     => (list . 5)
;; 7番目の文字から読み始め、9番目の文字で読み終える
(read-from-string "(list 112)" 6 8)
     => (11 . 8)

standard-input Variable
この変数はデフォルトの入力ストリーム、 つまり、引数streamnilである場合にreadが使う ストリームを保持する。


Node:Output Streams, Next:, Previous:Input Functions, Up:Read and Print

出力ストリーム

出力ストリームは表示で生成した文字群をどのように扱うかを指定します。 ほとんどの表示関数は省略可能な引数として出力ストリームを受け付けます。 出力ストリームとして使える型は以下のとおりです。

buffer
出力文字はバッファbufferのポイント位置に挿入される。 文字が挿入されるたびにポイント位置は進められる。
marker
出力文字はマーカmarkerがあるバッファのマーカ位置に挿入される。 文字を挿入するたびにマーカ位置は進められる。 ストリームがマーカであるときには、バッファのポイント位置は影響せず、 この種の表示ではポイントを移動しない。
function
出力文字は関数functionに渡され、この関数が文字の保存に責任を持つ。 1つの文字を引数として出力する文字数の回数だけ呼び出され、 読者の望む場所に文字を保存する責任を持つ。
t
出力文字はエコー領域に表示される。
nil
出力ストリームとしてnilを指定すると、 standard-outputの値をかわりに使うことを意味する。 その値はデフォルト出力ストリームであり、 nil以外であること。
symbol
出力ストリームとしてのシンボルは、 そのシンボルの(あれば)関数定義と等価である。

正当な出力ストリームの多くは、入力ストリームとしても正当です。 入力ストリームと出力ストリームの違いは、 オブジェクト型の違いというよりは、 読者がLispオブジェクトをどのように使うかです。

バッファを出力ストリームとして使った例を示します。 ポイントの初期位置は以下に示すようにthehの直前にあります。 終了後でも、ポイントは同じhの直前に位置しています。

---------- Buffer: foo ----------
This is t-!-he contents of foo.
---------- Buffer: foo ----------

(print "This is the output" (get-buffer "foo"))
     => "This is the output"

---------- Buffer: foo ----------
This is t
"This is the output"
-!-he contents of foo.
---------- Buffer: foo ----------

つぎは、マーカを出力ストリームとして用いた例です。 バッファfooのマーカの初期位置は、 単語thethのあいだにあります。 終了後には、マーカは挿入したテキストを越えて同じhの直前に位置します。 ポイント位置はなんの影響もないことに注意してください。

---------- Buffer: foo ----------
This is the -!-output
---------- Buffer: foo ----------

(setq m (copy-marker 10))
     => #<marker at 10 in foo>

(print "More output for foo." m)
     => "More output for foo."

---------- Buffer: foo ----------
This is t
"More output for foo."
he -!-output
---------- Buffer: foo ----------

m
     => #<marker at 34 in foo>

つぎは、エコー領域への出力の例です。

(print "Echo Area output" t)
     => "Echo Area output"
---------- Echo Area ----------
"Echo Area output"
---------- Echo Area ----------

最後は、関数を出力ストリームとして使った例を示します。 関数eat-outputは与えられた文字を受け取り、 それをリストlast-outputの先頭にコンスします (see Building Lists)。 終了後には、リストがすべての出力文字を保持していますが逆順です。

(setq last-output nil)
     => nil

(defun eat-output (c)
  (setq last-output (cons c last-output)))
     => eat-output

(print "This is the output" 'eat-output)
     => "This is the output"

last-output
     => (10 34 116 117 112 116 117 111 32 101 104
    116 32 115 105 32 115 105 104 84 34 10)

リストの順番を逆にすれば正しい順序の出力になります。

(concat (nreverse last-output))
     => "
\"This is the output\"
"

concatを呼び出してリストを文字列に変換し、 内容を読みやすいようにしました。


Node:Output Functions, Next:, Previous:Output Streams, Up:Read and Print

出力関数

本節ではLispオブジェクトを表示する、 つまり、オブジェクトを表示表現に変換するLisp関数について述べます。

Emacsの表示関数のなかには、正しく読み取れるように クォート文字を出力に追加するものがあります。 使用されるクォート文字は"\です。 これらは、文字列とシンボルを区別したり、 文字列やシンボル内の句読点文字を読み取るときに区切り文字として扱うこと を防ぎます。 詳しくはSee Printed Representation。 出力関数を選べば、クォートのありなしを指定できます。

テキストをLispシステムへ読み取る意図がある場合には、 曖昧さを避けるためにクォート文字付きで表示するべきです。 Lispプログラマに対してLispオブジェクトを明確に記述する場合も同様です。 しかし、人間向けの見やすい出力が目的であれば、 クォートせずに表示するのが普通はよいでしょう。

Lispオブジェクトはそれ自身を参照できます。 自己参照しているオブジェクトを普通の方法で表示するには 無限のテキストが必要であり、 そのような試みは無限再帰をもたらします。 Emacsはそのような再帰を検出し、 すでに表示したオブジェクトを再帰的に表示するかわりに #levelを表示します。 たとえば、#0は、現在の表示操作においてレベル0のオブジェクトを 再帰的に参照することを示します。

(setq foo (list nil))
     => (nil)
(setcar foo foo)
     => (#0)

以下の関数では、streamは出力ストリームを表します。 (出力ストリームについては前節を参照。) streamnilであったり省略すると、 standard-outputの値をデフォルトにします。

print object &optional stream Function
関数printは便利な表示方法である。 オブジェクトobjectの表示表現を ストリームstreamに出力し、 objectの前後に改行を1つずつ表示する。 クォート文字を使う。 printobjectを返す。 たとえばつぎのとおり。
(progn (print 'The\ cat\ in)
       (print "the hat")
       (print " came back"))
     -|
     -| The\ cat\ in
     -|
     -| "the hat"
     -|
     -| " came back"
     -|
     => " came back"

prin1 object &optional stream Function
この関数はオブジェクトobjectの表示表現を ストリームstreamに出力する。 printのようには出力を区切る改行を表示しないが、 printと同様にクォート文字を用いる。 objectを返す。
(progn (prin1 'The\ cat\ in)
       (prin1 "the hat")
       (prin1 " came back"))
     -| The\ cat\ in"the hat"" came back"
     => " came back"

princ object &optional stream Function
この関数はオブジェクトobjectの表示表現を ストリームstreamに出力する。 objectを返す。

この関数は、readではなく人が読みやすい出力を意図しており、 クォート文字を挿入せず、文字列を囲むダブルクォートも出力しない。 空白も追加しない。

(progn
  (princ 'The\ cat)
  (princ " in the \"hat\""))
     -| The cat in the "hat"
     => " in the \"hat\""

terpri &optional stream Function
この関数はストリームstreamに改行を出力する。 関数名は『terminate print』の略。

write-char character &optional stream Function
この関数は文字characterをストリームstreamへ出力する。 characterを返す。

prin1-to-string object &optional noescape Function
この関数は同じ引数に対してprin1が表示するであろう テキストから成る文字列を返す。
(prin1-to-string 'foo)
     => "foo"
(prin1-to-string (mark-marker))
     => "#<marker at 2773 in strings.texi>"

noescapenil以外であると、 出力にはクォート文字を使わない。 (この引数は、Emacs 19版以降で使える。)

(prin1-to-string "foo")
     => "\"foo\""
(prin1-to-string "foo" t)
     => "foo"

文字列としてのLispオブジェクトの表示表現を得るための別の方法については、 String Conversionformatを参照。

with-output-to-string body... Macro
このマクロは、standard-outputを文字列への出力と設定して フォームbodyを実行する。 そして、その文字列を返す。

たとえば、カレントバッファの名前がfooであると

(with-output-to-string
  (princ "The buffer is ")
  (princ (buffer-name)))

"The buffer is foo"を返す。


Node:Output Variables, Previous:Output Functions, Up:Read and Print

出力に影響する変数

standard-output Variable
この変数の値はデフォルトの出力ストリーム、つまり、 引数streamnilの場合に表示関数が用いるストリーム。

print-escape-newlines Variable
この変数がnil以外であると、 文字列内の改行文字を\n、ページ送り文字を\fと表示する。 通常、これらの文字は実際の改行やページ送りとして表示される。

この変数は、クォート付きで表示する表示関数prin1printに影響を与える。 princには影響しない。 prin1を用いた例を示す。

(prin1 "a\nb")
     -| "a
     -| b"
     => "a
b"

(let ((print-escape-newlines t))
  (prin1 "a\nb"))
     -| "a\nb"
     => "a
b"

2番目の式では、prin1の呼び出し中には print-escape-newlinesのローカル束縛が有効であるが、 結果を表示するときには有効ではない。

print-escape-nonascii Variable
この変数がnil以外であると、 クォート付きで表示する出力関数prin1printは、 文字列内のユニバイト非ASCII文字を無条件で バックスラッシュ列として表示する。

これらの関数は、出力ストリームがマルチバイトバッファや マルチバイトバッファのマーク位置であると、 この変数の値に関係なくユニバイト非ASCII文字に対して バックスラッシュ列を用いる。

print-escape-multibyte Variable
この変数がnil以外であると、 クォート付きで表示する表示関数prin1printは、 文字列内のマルチバイト非ASCII文字を無条件で バックスラッシュ列として表示する。

これらの関数は、出力ストリームがユニバイトバッファや ユニバイトバッファのマーク位置であると、 この変数の値に関係なくマルチバイト非ASCII文字に対して バックスラッシュ列を用いる。

print-length Variable
この変数の値は、任意のリスト、ベクトル、ブールベクトルを表示するときの 最大要素数である。 表示するオブジェクトがこれより多くの要素を持つと、 「…」で省略する。

値がnil(デフォルト)であると無制限。

(setq print-length 2)
     => 2
(print '(1 2 3 4 5))
     -| (1 2 ...)
     => (1 2 ...)

print-level Variable
この変数の値は、表示するときの括弧や角括弧の入れ子の最大の深さ。 この制限を越える任意のリストやベクトルは「…」で省略する。 値がnil(デフォルト)であると無制限。


Node:Minibuffers, Next:, Previous:Read and Print, Up:Top

ミニバッファ

ミニバッファ(minibuffer)は、単純な数値前置引数ではなく、 より複雑な引数を読み取るためにEmacsのコマンドが使う特別なバッファです。 これらの引数には、ファイル名、バッファ名、 (M-xでの)コマンド名があります。 ミニバッファは、エコー領域と同様に、フレームの最下行に表示されますが、 引数を読み取るときにのみ表示されます。


Node:Intro to Minibuffers, Next:, Up:Minibuffers

ミニバッファの紹介

ほとんどの意味において、ミニバッファはEmacsの普通のバッファです。 編集コマンドなどのバッファでのほとんどの操作は、 ミニバッファでも普通に動作します。 しかし、バッファを操作するコマンドの多くは、 ミニバッファには適用できません。 ミニバッファの名前はつねに*Minibuf-numberという形式であって、 変更できません。 ミニバッファはミニバッファ専用の特別なウィンドウだけに表示されます。 これらのウィンドウはつねにフレームの最下行に現れます。 (ミニバッファを持たないフレームや、 ミニバッファ用ウィンドウのみの特殊なフレームもある。 Minibuffers and Framesを参照。)

ミニバッファ用のウィンドウは通常は1行だけです。 ウィンドウサイズを変更するコマンドで一時的に大きさを変えられますが、 ミニバッファから抜けると通常サイズに戻ります。 ミニバッファ用ウィンドウのサイズを恒久的に変更するには、 ミニバッファを使っていないときに、フレームの別のウィンドウにおいて ウィンドウサイズを変更するコマンドを使います。 ミニバッファだけを持つフレームの場合、 フレームのサイズを変更すればミニバッファのサイズを変更できます。

すでにミニバッファが活性であるときにコマンドがミニバッファを使用することを 再帰ミニバッファと呼びます。 最初のミニバッファの名前は *Minibuf-0*です。 再帰ミニバッファは、名前の最後の数を増やして命名します。 (名前は空白で始まるため、通常のバッファの一覧には表示されない。) 再帰ミニバッファの中で、もっとも内側の(つまりもっとも再帰が深い)ものが 活性なミニバッファです。 これを単にミニバッファと呼びます。 変数enable-recursive-minibuffersを設定すれば、 再帰ミニバッファを許可したり禁止できます。 あるいは、コマンドシンボルにこの名前の属性を入れます (see Minibuffer Misc)。

他のバッファと同様に、ミニバッファは 複数のローカルキーマップ(see Keymaps)を使うことがあります。 これらには、さまざまな終了コマンドや補完コマンド(see Completion) が含まれます。


Node:Text from Minibuffer, Next:, Previous:Intro to Minibuffers, Up:Minibuffers

ミニバッファでのテキスト文字列の読み取り

多くの場合、テキストを文字列として読み取るためにミニバッファを使います。 Lispオブジェクトのテキスト表現を読み取るためにも使えます。 ミニバッファでの入力のもっとも基本的な関数は read-from-minibufferであり、どちらの目的にも使えます。

多くの場合、Lisp関数の途中でミニバッファの入力関数を呼ぶべきではありません。 そのかわりに、interactiveの指定で、 コマンドの引数を読み取る操作の一部として すべてのミニバッファ入力を行います。 See Defining Commands

read-from-minibuffer prompt-string &optional initial-contents keymap read hist default inherit-input-method Function
この関数は、ミニバッファから入力を得るもっとも汎用の方法である。 デフォルトでは、任意のテキストを受け取り文字列として返す。 しかし、readnil以外であれば、 readを用いてテキストを Lispオブジェクトへ変換する(see Input Functions)。

この関数がまず行うことは、ミニバッファを活性にし、 プロンプトprompt-stringとともに表示することである。 prompt-stringは文字列であること。 これで、ユーザーはミニバッファでテキストを編集できるようになる。

ユーザーがミニバッファを抜けるコマンドを打つと、 read-from-minibufferは ミニバッファ内のテキストから戻り値を構築する。 通常、当該テキストを含む文字列を返す。 しかし、readnil以外であると、 read-from-minibufferはテキストを読み取った結果である Lispオブジェクトを評価せずに返す。 (読み取りについてはsee Input Functions。)

引数defaultは、履歴コマンドで使うデフォルト値を指定する。 これは文字列かnilであること。 readnil以外である場合、 ユーザーの入力が空であるときには、 readへの入力としてもdefaultを用いる。 しかし、(readnilである)通常の場合、 ユーザーの入力が空のとき、read-from-minibufferdefaultを返さずに空文字列""を返す。 この意味において、この関数は本章の他のミニバッファ用入力関数と異なる。

keymapnil以外であると、 ミニバッファのローカルキーマップとして用いる。 keymapを省略したりnilであると、 minibuffer-local-mapの値をキーマップとして用いる。 キーマップを指定することは、 補完などのさまざまな応用向けにミニバッファをカスタマイズする もっとも重要な方法である。

引数histは、ミニバッファでの入力を保存し履歴コマンドを使用可能に するために用いる履歴リスト変数を指定する。 デフォルトはminibuffer-historyである。 see Minibuffer History

変数minibuffer-allow-text-propertiesnil以外であると、 返される文字列には、ミニバッファで指定されたテキスト属性が含まれる。 さもなければ、値を返すときにすべてのテキスト属性を取り除く。

引数inherit-input-methodnil以外であると、 ミニバッファに入るまえにどのバッファにいたかに関わらず、 そのバッファから現在の入力方式(see Input Methods)と enable-multibyte-characters(see Text Representations)の設定を 継承する。

initial-contentsが文字列であれば、 read-from-minibufferは、 ユーザーがテキスト編集を始めるまえに、 この文字列をミニバッファに挿入しその末尾にポイントを置く。 この文字列を初期内容とするミニバッファが現れる。

あるいは、initial-contentsは、 (string . position)という形式のコンスセルでもよい。 これは、文字列stringをミニバッファに挿入し、 ポイントは末尾にではなく 先頭からposition番目の文字に置くことを意味する。

使用上の注意: 引数initial-contentsdefaultは、 多かれ少なかれ同じことを行う代替方法を提供する。 read-from-minibufferの1つの呼び出しにおいて、 両者の機能を同時に使うことに意味はない。 一般には、defaultを使うことを勧める。 というのは、ユーザーがデフォルト値を望む場合にはデフォルト値を挿入でき、 それ以外の場合にはデフォルト値を削除しなくてもよいからである。

read-string prompt &optional initial history default inherit-input-method Function
この関数はミニバッファから文字列を読み取り、それを返す。 引数promptinitialは、 read-from-minibufferと同様に使われる。 使用するキーマップはminibuffer-local-mapである。

省略可能な引数historyは、nil以外であると、 履歴リストと(省略可能な)リスト内での初期位置を指定する。 省略可能な引数defaultは、 ユーザー入力が空の場合に返されるデフォルト値であり、文字列であること。 省略可能な引数inherit-input-methodは、 カレントバッファの入力方式を継承するかどうかを指定する。

この関数は関数read-from-minibufferの インターフェイスを単純化したものである。

(read-string prompt initial history default inherit)
==
(let ((value
       (read-from-minibuffer prompt initial nil nil
                             history default inherit)))
  (if (equal value "")
      default
    value))

minibuffer-allow-text-properties Variable
この変数がnilであると、 read-from-minibufferはミニバッファで指定されたすべての テキスト属性を返すまえに取り除く。 すべてのミニバッファがread-from-minibufferを使うので、 この変数はすべてのミニバッファ入力に適用される。

この変数の値に関わらず、 補完関数は無条件にテキスト属性を廃棄することに注意。

minibuffer-local-map Variable
ミニバッファから読み取るときのデフォルトのローカルキーマップ。 デフォルトでは、以下のバインディングである。
C-j
exit-minibuffer
<RET>
exit-minibuffer
C-g
abort-recursive-edit
M-n
next-history-element
M-p
previous-history-element
M-r
next-matching-history-element
M-s
previous-matching-history-element

read-no-blanks-input prompt &optional initial inherit-input-method Function
この関数はミニバッファから文字列を読み取るが、 入力には白文字を許さず、白文字は入力を終らせる。 引数promptinitialinherit-input-methodは、 read-from-minibufferと同様に使われる。

これは関数read-from-minibufferの インターフェイスを単純化したものであり、 引数keymapとしてminibuffer-local-ns-mapの値を渡す。 キーマップminibuffer-local-ns-mapでは C-qを再バインドしないため、 クォートすれば空白を文字列に含めることができる

(read-no-blanks-input prompt initial)
==
(read-from-minibuffer prompt initial minibuffer-local-ns-map)

minibuffer-local-ns-map Variable
この組み込み変数は、関数read-no-blanks-inputが ミニバッファ用のローカルキーマップとして使うキーマップである。 デフォルトでは、minibuffer-local-mapのバインディングに加えて 以下のバインディングである。
<SPC>
exit-minibuffer
<TAB>
exit-minibuffer
?
self-insert-and-exit


Node:Object from Minibuffer, Next:, Previous:Text from Minibuffer, Up:Minibuffers

ミニバッファでのLispオブジェクトの読み取り

本節では、ミニバッファでLispオブジェクトを読み取る関数について述べます。

read-minibuffer prompt &optional initial Function
この関数はミニバッファを用いてLispオブジェクトを読み取り、 それを評価せずに返す。 引数promptinitialは、 read-from-minibufferと同様に使われる。

これは関数read-from-minibufferの インターフェイスを単純化したものである。

(read-minibuffer prompt initial)
==
(read-from-minibuffer prompt initial nil t)

初期入力として文字列"(testing)"を与えた例を示す。

(read-minibuffer
 "Enter an expression: " (format "%s" '(testing)))

;; 以下のようにミニバッファが表示される

---------- Buffer: Minibuffer ----------
Enter an expression: (testing)-!-
---------- Buffer: Minibuffer ----------

デフォルトとして初期入力を使うには、ユーザーはただちに<RET>を打てばよい。 あるいは、入力を編集する。

eval-minibuffer prompt &optional initial Function
この関数はミニバッファを用いてLisp式を読み取り、 それを評価してその結果を返す。 引数promptinitialは、 read-from-minibufferと同様に使われる。

この関数はread-from-minibufferの インターフェイスを単純化したものである。

(eval-minibuffer prompt initial)
==
(eval (read-minibuffer prompt initial))

edit-and-eval-command prompt form Function
この関数はミニバッファを用いてLisp式を読み取り、それを評価する。 このコマンドとeval-minibufferとの違いは、 初期フォームformを省略できないことであり、 このフォームをテキスト文字列としではなく表示表現に 変換するLispオブジェクトとして扱うことである。 prin1を用いて表示するので、 これが文字列であると初期テキストにはダブルクォート文字(")が現れる。 see Output Functions

edit-and-eval-commandはまず、promptをプロンプトとして ミニバッファを活性にする。 続いて、ミニバッファにformの表示表現を挿入し、ユーザーに編集させる。 ユーザーがミニバッファから抜けると、 編集後のテキストをreadで読み取り評価する。 評価結果がedit-and-eval-commandの値になる。

以下の例では、すでに正しいフォームである 初期テキストの式をユーザーに提示する。

(edit-and-eval-command "Please edit: " '(forward-word 1))

;; 上の式を評価後には、ミニバッファは以下のようになる

---------- Buffer: Minibuffer ----------
Please edit: (forward-word 1)-!-
---------- Buffer: Minibuffer ----------

ただちに<RET>を打つと、 ミニバッファから抜けて式を評価するので、 ポイントを1単語分先へ進めることになる。 この例では、edit-and-eval-commandnilを返す。


Node:Minibuffer History, Next:, Previous:Object from Minibuffer, Up:Minibuffers

ミニバッファの履歴

ミニバッファ履歴リスト(minibuffer history list)は ミニバッファでの以前の入力を記録し、 ユーザーがそれらを手軽に再利用できるようにします。 履歴リストは実際にはシンボルでありリストではありません。 最新のものが先頭にある(以前の入力の)文字列のリストを値とする変数です。

異なる種類の入力に用いる多くの別々の履歴リストがあります。 ミニバッファを利用するたびに適した履歴リストを指定するのは、 Lispプログラマの責任です。

基本的なミニバッファ入力関数 read-from-minibuffercompleting-readの両者は、 読者が指定する履歴リストを省略可能な引数histとして受け付けます。 指定可能な値はつぎのとおりです。

variable
変数variable(シンボル)を履歴リストとして用いる。
(variable . startpos)
変数variable(シンボル)を履歴リストとして用い、 初期履歴位置をstartpos (履歴リストの最新要素を0とする整数)と仮定する。

startposを指定した場合、整合性を保つために、 履歴リストの当該要素をミニバッファの初期内容にも指定すること。

histを指定しなければ、 デフォルトの履歴リストminibuffer-historyを用いる。 その他の標準的な履歴リストについては以下を参照。 読者が独自の履歴リスト変数を作成してもよい。 初めて使用するまえに単にnilで初期化しておく。

read-from-minibuffercompleting-readの両者は 履歴リストに新たな要素を自動的に追加し、 リスト上の要素を再利用するためのコマンドをユーザーに提供する。 履歴リストを使うために読者のプログラムで行うべきことは、 履歴リストを初期化し必要なときにその名前を入力関数に渡すだけである。 ミニバッファ入力関数が履歴リストを使用していないときには、 履歴リストを変更しても安全である。

標準的なミニバッファ履歴リスト変数を以下にあげておく。

minibuffer-history Variable
ミニバッファの履歴入力用のデフォルトの履歴リスト。

query-replace-history Variable
query-replace(および同様のコマンド)の引数用の履歴リスト。

file-name-history Variable
ファイル名引数用の履歴リスト。

buffer-name-history Variable
バッファ名引数用の履歴リスト。

regexp-history Variable
正規表現引数用の履歴リスト。

extended-command-history Variable
拡張コマンド名である引数用の履歴リスト。

shell-command-history Variable
シェルコマンドである引数用の履歴リスト。

read-expression-history Variable
Lisp式として評価する引数用の履歴リスト。


Node:Completion, Next:, Previous:Minibuffer History, Up:Minibuffers

補完

補完(completion)とは、 名前の省略から始まる名前の残り部分を補充する機能です。 ユーザー入力を正しい名前のリストと比較し、 すでにユーザーが入力したものに名前が どの程度一致するかを決定することで補完します。 たとえば、C-x bswitch-to-buffer)と打って、 切り替えたいバッファ名の始めの数文字を打って <TAB>(minibuffer-complete)を打つと、 Emacsは可能な限りその名前を補充します。

Emacsの標準のコマンドは、 シンボル、ファイル、バッファ、プロセスの名前を補完できます。 本節の関数を用いれば、その他の種類の名前の補完も実装できます。

関数try-completionは補完のための基本関数です。 与えられた文字列の集まりから 初期文字列にもっとも適合する最長のものを返します。

関数completing-readは補完のための上位レベルの インターフェイスを提供します。 completing-readの呼び出しには、 正しい名前のリストを決定する方法を指定します。 この関数は、補完に有用なコマンドを数個のキーにバインドした ローカルキーマップを使うミニバッファを活性にします。 その他の関数は、特定の種類の名前を補完して読み取るために 単純化したインターフェイスを提供します。


Node:Basic Completion, Next:, Up:Completion

基本補完関数

2つの関数try-completionall-completionsは、 それ自身ではミニバッファを使いません。 これらについて本章で述べるのは、 ミニバッファを使う上位レベルの補完機能と同列にしておくためです。

try-completion string collection &optional predicate Function
この関数は、collectionにあるstringを補完する 共通の最長な部分文字列を返す。 collectionの値は、連想リスト、オブジェクト配列、あるいは、 実質的な文字列の集まりを返す関数(下記参照)であること。

補完では、collectionで指定した各補完候補と stringを比較する。 補完候補の先頭部分がstringに等しければ、 その補完候補は一致するという。 一致する補完候補がなければ、try-completionnilを返す。 たった1つの補完候補に一致し、かつ、完全に一致すれば、 try-completiontを返す。 さもなければ、一致する補完候補すべてに共通する最長の文字列を値とする。

collectionが連想リスト(see Association Lists)であると、 連想リストの要素のCAR群が補完候補の集まりになる。

collectionがオブジェクト配列(see Creating Symbols)であると、 オブジェクト配列内のすべてのシンボルの名前が補完候補の集まりになる。 グローバル変数obarrayは、インターンしたすべてのLispシンボルの 名前を収めたオブジェクト配列を保持する。

新たなオブジェクト配列を作成する唯一の正しい方法は、 まず空で作成してからinternで1つ1つシンボルを追加することである ことに注意。 なお、1つのシンボルを複数のオブジェクト配列にはインターンできない。

引数predicatenil以外である場合、 それは1引数の関数であること。 その関数は一致する補完候補の検査に使われ、 predicatenil以外を返す場合にのみ一致した候補とみなす。 predicateに渡す引数は、 (CARが文字列である)連想リストのコンスセルであるか、 オブジェクト配列からの(シンボル名ではない)シンボルである。

collectionには、関数であるシンボルを使うこともできる。 その関数には補完処理を完遂する責任がある。 try-completionはその関数が返したものを返す。 その関数は3引数、つまり、 stringpredicatenilで呼ばれる。 (第3引数がある理由は、 all-completionsでも同じ関数を使い、 いずれの場合にも適切に動作できるようにするため。) see Programmed Completion

以下の最初の例では、 文字列fooは連想リストの3つのCARに一致する。 すべての一致はfoobaで始まるため、これが結果になる。 2番目の例では、たった1つの一致があり、しかも、完全に一致するので、 値はtである。

(try-completion
 "foo"
 '(("foobar1" 1) ("barfoo" 2) ("foobaz" 3) ("foobar2" 4)))
     => "fooba"

(try-completion "foo" '(("barfoo" 2) ("foo" 3)))
     => t

つぎの例では、forwで始まるシンボルが多数あり、 それらはすべて単語forwardで始まる。 ほとんどのシンボルでは、これに-が続くが、 すべてがそうではないので、forwardまでしか補完できない。

(try-completion "forw" obarray)
     => "forward"

最後の例は、述語testの検査に通るのは3つの一致のうち2つだけである (文字列foobazは短すぎる)。 両者は文字列foobarで始まる。

(defun test (s)
  (> (length (car s)) 6))
     => test
(try-completion
 "foo"
 '(("foobar1" 1) ("barfoo" 2) ("foobaz" 3) ("foobar2" 4))
 'test)
     => "foobar"

all-completions string collection &optional predicate nospace Function
この関数はstringの補完すべてのリストを返す。 この関数の引数は、try-completionのものと同じである。

collectionが関数であると、 stringpredicatetの3引数で呼ばれる。 all-completionsはこの関数が返す値を返す。 see Programmed Completion

nospacenil以外であると、 stringが空白で始まらない限り、空白で始まる補完は無視する。

try-completionの例に示した関数testを用いた例を示す。

(defun test (s)
  (> (length (car s)) 6))
     => test

(all-completions
 "foo"
 '(("foobar1" 1) ("barfoo" 2) ("foobaz" 3) ("foobar2" 4))
 'test)
     => ("foobar1" "foobar2")

completion-ignore-case Variable
この変数の値がnil以外であると、 Emacsは補完において大文字小文字を区別しない。


Node:Minibuffer Completion, Next:, Previous:Basic Completion, Up:Completion

補完とミニバッファ

本節ではミニバッファからの補完による読み取り用の 基本インターフェイスについて述べます。

completing-read prompt collection &optional predicate require-match initial hist default inherit-input-method Function
この関数は、与えられた補完でユーザーを補佐して ミニバッファで文字列を読み取る。 文字列であるプロンプトpromptでミニバッファを活性にする。

実際の補完は、collectionpredicateを 関数try-completionに渡して行う。 これは、補完を用いるローカルキーマップでバインドされたコマンドで行われる。

require-matchnilであると、 ミニバッファでの入力に関わらず ミニバッファから抜けるコマンドは動作する。 require-matchtであると、 ミニバッファでの入力がcollectionの1つの要素に補完できない限り、 ミニバッファから抜ける通常のコマンドは動作しない。 require-matchnilでもtでもないと、 ミニバッファでの入力がcollectionの1つの要素に一致しない限り、 ミニバッファから抜けるコマンドは動作しない。

しかし、require-matchの値に関わらず、 空の入力はつねに許される。 その場合、completing-readdefaultを返す。 defaultの値は(nilでなければ)履歴コマンドを介しても ユーザーが使える。

ミニバッファが空の状態で<RET>を打つと、 ユーザーは空入力で抜けることができる。 そうすると、completing-read""を返す。 これにより、読み取った値に対してコマンドが使うどんなデフォルトでも指定できる。 require-matchの値、および、collectionに空文字列が 含まれるかどうかに関わらず、ユーザーはこのようにして<RET>で戻れる。

関数completing-readread-minibufferを呼び出すことで動作する。 require-matchnilであると、 キーマップとしてminibuffer-local-completion-mapを使い、 nil以外であるとminibuffer-local-must-match-mapを使う。 see Completion Commands

引数histは、入力を保存しミニバッファ履歴コマンドで 使う履歴リスト変数を指定する。 デフォルトはminibuffer-historyである。 see Minibuffer History

initialnil以外であると、 completing-readはこれを入力の一部としてミニバッファに挿入する。 これにより、ユーザーは補完コマンドとともに入力を編集できる。 ほとんどの場合、initialではなくdefaultを使うことを勧める。

引数inherit-input-methodnil以外であると、 ミニバッファに入るまえのカレントバッファがなんであれ、 カレントバッファから現在の入力方式(see Input Methods)と enable-multibyte-characters(see Text Representations) の設定を継承する。

組み込み変数completion-ignore-casenil以外であると、 大文字小文字を区別せずに候補に対して入力を比較する。 see Basic Completion

completing-readを用いた例を以下に示す。

(completing-read
 "Complete a foo: "
 '(("foobar1" 1) ("barfoo" 2) ("foobaz" 3) ("foobar2" 4))
 nil t "fo")

;; 上の式を評価するとミニバッファはつぎのようになる

---------- Buffer: Minibuffer ----------
Complete a foo: fo-!-
---------- Buffer: Minibuffer ----------

ユーザーが<DEL> <DEL> b <RET>を打つと、 completing-readbarfooを返す。

関数completing-readは、 補完を実際に行うコマンドに情報を渡すために3つの変数を束縛する。 3つの変数とは、minibuffer-completion-tableminibuffer-completion-predicateminibuffer-completion-confirmである。 これらについて詳しくは、Completion Commandsを参照。


Node:Completion Commands, Next:, Previous:Minibuffer Completion, Up:Completion

補完を行うミニバッファコマンド

本節では、補完を行うためにミニバッファで用いられるキーマップ、 コマンド、ユーザーオプションについて述べます。

minibuffer-local-completion-map Variable
completing-readは、 補完候補の1つと完全に一致しなくてもよい場合に ローカルキーマップとしてこの値を使う。 デフォルトでは、このキーマップのバインディングはつぎのとおり。
?
minibuffer-completion-help
<SPC>
minibuffer-complete-word
<TAB>
minibuffer-complete

他の文字はminibuffer-local-map (see Text from Minibuffer)と同様にバインドされる。

minibuffer-local-must-match-map Variable
completing-readは、 補完候補の1つと完全に一致する必要がある場合に ローカルキーマップとしてこの値を使う。 そのため、ミニバッファから無条件に抜けるコマンドexit-minibufferに バインドしたキーはない。 デフォルトでは、このキーマップのバインディングはつぎのとおり。
?
minibuffer-completion-help
<SPC>
minibuffer-complete-word
<TAB>
minibuffer-complete
C-j
minibuffer-complete-and-exit
<RET>
minibuffer-complete-and-exit

他の文字はminibuffer-local-mapと同様にバインドされる。

minibuffer-completion-table Variable
この変数の値は、ミニバッファでの補完に用いられる 連想リストやオブジェクト配列である。 これは、completing-readtry-completionに渡すものを 保持したグローバル変数である。 minibuffer-complete-wordなどの ミニバッファ補完コマンドで使用される。

minibuffer-completion-predicate Variable
この変数の値は、completing-readtry-completionへ渡す述語である。 この変数は、他のミニバッファ補完関数でも使われる。

minibuffer-complete-word コマンド
この関数は、ミニバッファの内容を多くても1単語分補完する。 ミニバッファの内容に対応する補完がたった1つであっても、 単語構成文字ではない文字以降は補充しない。 see Syntax Tables

minibuffer-complete コマンド
この関数は、ミニバッファの内容を可能な限り補完する。

minibuffer-complete-and-exit コマンド
この関数は、確認が必要でないとき、つまり、 minibuffer-completion-confirmnilであるときには、 ミニバッファの内容を補完後に抜ける。 確認が必要であるときには、 このコマンドをただちに繰り返すことで確認をとる。 このコマンドは、連続して2回呼ばれると、 確認しないようにプログラムしてある。

minibuffer-completion-confirm Variable
この変数の値がnil以外の場合、 Emacsはミニバッファから抜けるまえに補完を確認してくる。 関数minibuffer-complete-and-exitは、 抜けるまえにこの変数の値を検査する。

minibuffer-completion-help コマンド
この関数は、ミニバッファの現在の内容に対する補完のリストを作る。 引数collectionとして変数minibuffer-completion-tableの値を、 引数predicateとしてminibuffer-completion-predicateの値を 用いてall-completionsを呼び出すことで動作する。 補完のリストは、*Completions*という名前のバッファに テキストとして表示される。

display-completion-list completions Function
この関数は、通常はバッファであるストリームstandard-outputcompletionsを表示する。 (ストリームについては詳しくはsee Read and Print。) 引数completionsは、普通は、all-completionsが 返した補完のリストであるが、そうでなくてもよい。 各要素は、シンボルか文字列であり、その場合、そのまま表示される。 各要素が2つの文字列から成るリストである場合、 文字列を連結したものを表示する。

この関数は、minibuffer-completion-helpから呼ばれる。 以下のように、with-output-to-temp-bufferとともに 用いるのがもっとも一般的である。

(with-output-to-temp-buffer "*Completions*"
  (display-completion-list
    (all-completions (buffer-string) my-alist)))

completion-auto-help User Option
この変数がnil以外であると、 つぎの補充文字が一意に決まらない場合には、 自動的に補完のリストを表示する。


Node:High-Level Completion, Next:, Previous:Completion Commands, Up:Completion

高レベルの補完関数

本節では、特定の種類の名前を補完付きで読み取るための 高レベルの便利な関数について述べます。

多くの場合、これらの関数をLisp関数の途中では呼び出さないでください。 可能な場合には、interactiveの指定で、 コマンドの引数を読み取る操作の一部としてすべてのミニバッファ入力を 行ってください。 See Defining Commands

read-buffer prompt &optional default existing Function
この関数はバッファ名を読み取り、文字列として返す。 引数defaultはデフォルトの名前を表し、 ユーザーがミニバッファから空で抜け出したときに返される値である。 nil以外であるときには、文字列かバッファであること。 これはプロンプトとして現れるが、 ミニバッファには初期入力として挿入されない。

existingnil以外であると、 指定した名前は既存のバッファ名であること。 テキストが正しくないとミニバッファから抜ける通常のコマンドは動作せず、 <RET>は正しい名前を探すため補完を行う。 (しかし、defaultが正しいかどうかは検査しない。 ユーザーがミニバッファを空で抜ければ、 なんであろうとdefaultが返される。)

以下の例では、ユーザーはminibuffer.tと入力してから<RET>を打つ。 引数existingtであり、 入力した名前で始まる唯一のバッファ名はminibuffer.texiであるので、 この名前が値になる。

(read-buffer "Buffer name? " "foo" t)
;; 上の式を評価すると、ミニバッファは空で
;; つぎのようなプロンプトが表示される

---------- Buffer: Minibuffer ----------
Buffer name? (default foo) -!-
---------- Buffer: Minibuffer ----------

;; ユーザーはminibuffer.t <RET>と打つ
     => "minibuffer.texi"

read-buffer-function Variable
この変数は、バッファ名の読み取り方を指定する。 たとえば、この変数にiswitchb-read-bufferを設定すると、 バッファ名を読み取るためにread-bufferを呼び出す すべてのEmacsコマンドは、 バッファ名を読むためにパッケージiswitchbを使うようになる。

read-command prompt &optional default Function
この関数はコマンド名を読み取り、Lispシンボルとして返す。 引数promptは、read-from-minibufferと同様に使われる。 なんであってもcommandptを返せばコマンドであり、 commandptを返すシンボルはコマンド名であることに注意。 see Interactive Call

引数defaultは、ユーザー入力が空だった場合に返したい値を指定する。 これは、シンボルか文字列であること。 文字列であると、read-commandは、これを返すまえにインターンする。 defaultnilであると、デフォルトを指定しないことを意味し、 ユーザー入力が空であると戻り値はnilである。

(read-command "Command name? ")

;; 上の式を評価後には、ミニバッファは空で
;; つぎのようなプロンプトが表示される

---------- Buffer: Minibuffer ----------
Command name?
---------- Buffer: Minibuffer ----------

ユーザーがforward-c <RET>と打つと、 この関数はforward-charを返す。

関数read-commandcompleting-readのインターフェイスを 単純化したものである。 既存のLispシンボルの集まりから補完するために変数obarrayを使い、 コマンド名のみを対象とするために述語commandpを使う。

(read-command prompt)
==
(intern (completing-read prompt obarray
                         'commandp t nil))

read-variable prompt &optional default Function
この関数はユーザー変数の名前を読み取り、シンボルとして返す。

引数defaultは、ユーザー入力が空だった場合に返したい値を指定する。 これは、シンボルか文字列であること。 文字列であると、read-variableは、これを返すまえにインターンする。 defaultnilであると、デフォルトを指定しないことを意味し、 ユーザー入力が空であると戻り値はnilである。

(read-variable "Variable name? ")

;; 上の式を評価後には、ミニバッファは空で
;; つぎのようなプロンプトが表示される

---------- Buffer: Minibuffer ----------
Variable name? -!-
---------- Buffer: Minibuffer ----------

ユーザーがfill-p <RET>と打つと、 read-variablefill-prefixを返す。

この関数はread-commandに似ているが、 commandpのかわりに述語user-variable-pを使う。

(read-variable prompt)
==
(intern
 (completing-read prompt obarray
                  'user-variable-p t nil))
User-Chosen Coding Systemsの関数read-coding-systemread-non-nil-coding-systemも参照してください。


Node:Reading File Names, Next:, Previous:High-Level Completion, Up:Completion

ファイル名の読み取り

ここでは、ファイル名を読み取るように設計された高レベルの 別の補完関数について述べます。 デフォルトディレクトリの自動挿入などの特別な機能を提供します。

read-file-name prompt &optional directory default existing initial Function
この関数は、promptをプロンプトとし、 補完を行ってミニバッファでファイル名を読み取る。 defaultnil以外であると、 ユーザーが単に<RET>を打つと、この関数はdefaultを返す。 defaultが正しいかどうかは検査せず、 それがなんであれ、ユーザーがミニバッファを空で抜けるとそれを返す。

existingnil以外であると、 ユーザーは既存ファイルの名前を指定する必要がある。 <RET>は、可能ならば正しい名前に補完を行うが、 それが正しくない場合には抜けない。 existingの値がnilでもtでもないと、 <RET>は補完後の確認を必要とする。 existingnilであると、 存在しないファイルの名前も許す。

引数directoryは、相対ファイル名の補完に用いるディレクトリを指定する。 insert-default-directorynil以外であると、 初期入力としてdirectoryをミニバッファに挿入する。 カレントバッファのdefault-directoryの値がデフォルトになる。

initialを指定すると、 (directoryがあればそれを挿入後に)バッファに 挿入される初期ファイル名になる。 この場合、ポイントはinitialの先頭に置かれる。 initialのデフォルトはnilであり、 いかなるファイル名も挿入しない。 initialの動作を見るには、コマンドC-x C-vを試してほしい。 注意: ほとんどの場合、initialではなくdefaultを使うことを勧める。

例を示す。

(read-file-name "The file is ")

;; 上の式を評価後には、ミニバッファはつぎのようになる

---------- Buffer: Minibuffer ----------
The file is /gp/gnu/elisp/-!-
---------- Buffer: Minibuffer ----------

manual <TAB>を打つと、つぎのようになる。

---------- Buffer: Minibuffer ----------
The file is /gp/gnu/elisp/manual.texi-!-
---------- Buffer: Minibuffer ----------

ユーザーが<RET>と打つと、 read-file-nameは ファイル名を文字列"/gp/gnu/elisp/manual.texi"として返す。

insert-default-directory User Option
この変数はread-file-nameが使う。 その値は、read-file-nameが、 デフォルトディレクトリの名前と(あれば)初期ファイル名を ミニバッファに入れて動作を開始するかどうかを制御する。 この変数の値がnilであると、 read-file-nameは (引数initialで初期入力を指定しない限り) ミニバッファに初期入力を入れない。 その場合でも、相対ファイル名の補完には デフォルトディレクトリを使うが表示はしない。

例を示す。

;; デフォルトディレクトリを入れて始める
(let ((insert-default-directory t))
  (read-file-name "The file is "))

---------- Buffer: Minibuffer ----------
The file is ~lewis/manual/-!-
---------- Buffer: Minibuffer ----------

;; ミニバッファは空であり、プロンプトのみ
(let ((insert-default-directory nil))
  (read-file-name "The file is "))

---------- Buffer: Minibuffer ----------
The file is -!-
---------- Buffer: Minibuffer ----------


Node:Programmed Completion, Previous:Reading File Names, Up:Completion

プログラム補完

意図した補完候補を持った連想リストやオブジェクト配列を 作成することが困難な場合もあります。 そのような場合、与えられた文字列に対する補完を計算する 独自の関数を与えることができます。 これをプログラム補完(programmed completion)と呼びます。

この機能を使うには、completing-readの引数collectionに 関数定義を持つシンボルを渡します。 関数completing-readは、 try-completionall-completionsに 読者の補完関数を渡すようにして、読者の関数にすべてを任せます。

補完関数はつぎの3つの引数を受け取ります。

3つの操作型に対応してフラグの値は3つあります。

補完関数collectionには関数シンボルに加えて、 ラムダ式(関数であるリスト)も許すほうが 一貫性があって見通しがよいはずですが、それは不可能です。 リストには補完候補表としての意味がすでにあり、連想リストがそれです。 関数としての可能性もある通常の連想リストの扱いに失敗するようでは、 信頼性がなくなります。 そのため、読者が補完に使用したい関数は、 シンボルに入れておく必要があるのです。

Emacsは、ファイル名の補完にはプログラム補完を用います。 See File Name Completion


Node:Yes-or-No Queries, Next:, Previous:Completion, Up:Minibuffers

Yes/Noの問い合わせ

本節ではユーザーにyes/noを問い合わせるための関数について述べます。 関数y-or-n-pには、1文字で答えます。 誤った答えでも重大な問題に至らないような問い合わせに便利です。 yes-or-no-pには3文字か4文字で答える必要があるため、 より重要な問い合わせに適しています。

これらの関数がマウスを使って起動されたコマンドから呼ばれると、 より正確には、last-nonmenu-event(see Command Loop Info)が nilかリストであると、 関数は問い合わせのための対話ボックスやポップアップメニューを使います。 さもなければ、キーボード入力を使います。 呼び出しにおいてlast-nonmenu-eventに適切な値を束縛することで マウスかキーボード入力の使用を強制できます。

厳密にいえば、yes-or-no-pはミニバッファを使いますが、 y-or-n-pは使いません。 ですが、両者をここで説明しておきます。

y-or-n-p prompt Function
この関数はユーザーに問い合わせ、エコー領域で入力を待ちます。 ユーザーがyを打てばtを返し、 nを打てばnilを返します。 さらに、<SPC>を「y」、<DEL>を「n」ともみなします。 C-]C-gのように『中断』ともみなします。 というのは、問い合わせはミニバッファを使っているようにみえるので、 これから抜けるためにユーザーがC-]を使いそうだからである。 応答は1文字であり、<RET>で終える必要はない。 大文字と小文字は同じ意味である。

『問い合わせ』では、エコー領域にpromptを表示し、 文字列(y or n) が続きます。 入力が正しい応答(yn<SPC><DEL>、中断など)でないと、 関数はPlease answer y or n.を表示して 問い合わせるを繰り返す。

応答は編集できないので、この関数は実際にはミニバッファを使わない。 ミニバッファが使うのと同じ画面領域を使う エコー領域(see The Echo Area)を実際には使う。 問い合わせ中は、カーソルはエコー領域に移動する。

応答とその意味は、 たとえynであっても組み込まれているわけではない。 キーマップquery-replace-mapがそれらを指定する。 see Search and Replace

以下の例では、ユーザーはまずqを打つが、これは正しくない。 つぎのプロンプトに対して、ユーザーはyを打つ。

(y-or-n-p "Do you need a lift? ")

;; 上の式を評価後には、エコー領域には
;; つぎのプロンプトが表示される

---------- Echo area ----------
Do you need a lift? (y or n)
---------- Echo area ----------

;; ユーザーがqを打つと、つぎのようになる

---------- Echo area ----------
Please answer y or n.  Do you need a lift? (y or n)
---------- Echo area ----------

;; ユーザーが正しい応答を打つと
;; 問い合わせのうしろに表示される

---------- Echo area ----------
Do you need a lift? (y or n) y
---------- Echo area ----------

ここでは、エコー領域のメッセージを複数行示したが、 実際には、1度に1つのメッセージだけが表示される。

y-or-n-p-with-timeout prompt seconds default-value Function
y-or-n-pと同様だが、ユーザーがseconds秒以内に答えないと、 入力を待たずにdefault-valueを返す。 これにはタイマを使う。 Timersを参照。 引数secondsは整数でも浮動小数点でもよい。

yes-or-no-p prompt Function
この関数はユーザーに問い合わせ、ミニバッファでの入力を仮定する。 ユーザーがyesを入力するとtを返し、 noを入力するとnilを返す。 応答を終えるためにユーザーは<RET>を打つ必要がある。 大文字と小文字は同じ意味である。

yes-or-no-pは、まず、promptに続けて (yes or no) をエコー領域に表示する。 ユーザーは正しい応答の1つを入力する必要がある。 さもないと、この関数はPlease answer yes or no.を2秒ほど 表示してから問い合わせを繰り返す。

yes-or-no-py-or-n-pよりもユーザーの手間を必要とし、 より重要な決定に適している。

例を示す。

(yes-or-no-p "Do you really want to remove everything? ")

;; 上の式を評価後には、つぎのプロンプトが
;; 空のミニバッファとともに表示される

---------- Buffer: minibuffer ----------
Do you really want to remove everything? (yes or no)
---------- Buffer: minibuffer ----------

ユーザーは、まずy <RET>を打つが、 この関数は完全な単語yesを要求するので正しくない。 以下のプロンプトを少し時間をおいて表示する。

---------- Buffer: minibuffer ----------
Please answer yes or no.
Do you really want to remove everything? (yes or no)
---------- Buffer: minibuffer ----------


Node:Multiple Queries, Next:, Previous:Yes-or-No Queries, Up:Minibuffers

複数のY/Nの問い合わせ

各バッファについて『バッファを保存するか』などの 一連の単純な問い合わせをする場合には、 個々に問い合わせるかわりに map-y-or-n-pを用いてまとめて問い合わせるべきです。

map-y-or-n-p prompter actor list &optional help action-alist Function
この関数は、各問について1文字の応答をエコー領域から読み取ることで、 ユーザーに一連の問い合わせを行う。

listの値は、問い合わせ対象のオブジェクトを指定する。 オブジェクトのリストであるか、生成関数であること。 関数である場合、それは引数なしで呼ばれ、 つぎの問い合わせ対象のオブジェクトを返すか、 問い合わせの終了を意味するnilを返す。

引数prompterは、各問い合わせをどのように問うかを指定する。 prompterが文字列であると、問い合わせ文はつぎのように計算される。

(format prompter object)

ここで、objectは(listから得た) 問い合わせ対象のオブジェクトである。

文字列でなければ、prompterは 1引数(問い合わせ対象のオブジェクト)の関数であり、 問い合わせ文を返す。 値が文字列であれば、それがユーザーへの問い合わせ文になる。 関数は、(ユーザーに問い合わせずに) 当該オブジェクトを処理することを意味するtか、 (ユーザーに問い合わせずに)当該オブジェクトを無視することを意味する nilを返してもよい。

引数actorは、ユーザーの応答に対してどのように動作するかを指定する。 これは1引数の関数であり、ユーザーが「はい」と答えたオブジェクトで 呼ばれる。 引数は、つねにlistから得たオブジェクトである。

引数helpを指定する場合、つぎの形のリストであること。

(singular plural action)

ここで、 singularは操作対象のオブジェクトを 記述する単数形の名詞を含んだ文字列であり、 pluralは対応する複数形の名詞であり、 actionは動作を記述する他動詞であること。

helpを指定しないと、デフォルトは ("object" "objects" "act on")である。

各問い合わせでは、ユーザーは当該対象オブジェクトに対する操作に yYSPCで答える。 nN、<DEL>は、そのオブジェクトを無視する。 !はそのオブジェクトを含めて後続のものも処理する。 <ESC>やqは(後続のオブジェクトをすべて無視して)抜ける。 .(ピリオド)は現在の対象オブジェクトを処理してから抜ける。 C-hはヘルプメッセージを表示する。 これらは、query-replaceが受け付ける応答と同じである。 キーマップquery-replace-mapが、 query-replaceと同様に map-y-or-n-pに対する(応答の)意味を定義する。 Search and Replaceを参照。

action-alistを使って、 可能な応答とそれらの意味を追加指定することもできる。 これは、(char function help)の形の要素から成る 連想リストであり、それぞれが1つの追加応答を定義する。 この要素の中で、 charは(応答である)1つの文字、 functionは1引数(listからのオブジェクト)の関数、 helpは文字列である。

ユーザーがcharで答えると、 map-y-or-n-pfunctionを呼び出す。 これがnil以外を返せば、当該オブジェクトを『処理』したとみなして、 map-y-or-n-plistのつぎのオブジェクトに移る。 nilであると、同じオブジェクトについてプロンプトを繰り返す。

map-y-or-n-pがマウスを使って起動されたコマンドから呼ばれると、 より正確には、last-nonmenu-event(see Command Loop Info)が、 nilかリストであると、 関数は問い合わせのための対話ボックスやポップアップメニューを使う。 その場合、キーボード入力やエコー領域は使わない。 呼び出しにおいてlast-nonmenu-eventに適切な値を束縛することで マウスかキーボード入力の使用を強制できる。

map-y-or-n-pの戻り値は、処理したオブジェクトの個数である。


Node:Reading a Password, Next:, Previous:Multiple Queries, Up:Minibuffers

パスワードの読み取り

別のプログラムへ渡すパスワードを読み取るには、 関数read-passwdを使います。

read-passwd prompt &optional confirm default Function
この関数は、プロンプトpromptを表示してパスワードを読み取る。 ユーザーが入力するパスワードは表示せず、 そのかわりにパスワードの各文字ごとに.を表示する。

省略可能な引数confirmnil以外であると、 パスワードを2回読み取り、両者が同一である必要がある。 同一でないと、連続して2回同じパスワードを打つまで ユーザーは何度でも繰り返す必要がある。

省略可能な引数defaultは、ユーザーが空のパスワードを 入力したときに返すデフォルトのパスワードを指定する。 defaultnilであると、 read-passwdはそのような場面では空文字列を返す。


Node:Minibuffer Misc, Previous:Reading a Password, Up:Minibuffers

ミニバッファに関するその他

本節では、ミニバッファに関係する他の基本関数や変数について述べます。

exit-minibuffer コマンド
このコマンドは活性なミニバッファから抜ける。 通常、ミニバッファのローカルキーマップでキーにバインドされる。

self-insert-and-exit コマンド
このコマンドは(Command Loop Infolast-command-charにある) 最新のキーボード入力文字を活性なミニバッファに挿入してから抜ける。

previous-history-element n コマンド
このコマンドは、ミニバッファの内容を n番目まえの(古い)履歴要素の値で置き換える。

next-history-element n コマンド
このコマンドは、ミニバッファの内容を n番目先のより新しい履歴要素の値で置き換える。

previous-matching-history-element pattern コマンド
このコマンドは、ミニバッファの内容を pattern(正規表現)に一致するまえの(古い)履歴要素の値で置き換える。

next-matching-history-element pattern コマンド
このコマンドは、ミニバッファの内容を pattern(正規表現)に一致するつぎの(新しい)履歴要素の値で置き換える。

minibuffer-prompt Function
この関数は、現在活性なミニバッファのプロンプト文字列を返す。 活性なミニバッファがなければnilを返す。

minibuffer-prompt-width Function
この関数は、現在活性なミニバッファのプロンプト文字列の表示幅を返す。 活性なミニバッファがなければ0を返す。

minibuffer-setup-hook Variable
ミニバッファに入るたびに実行されるノーマルフック。 see Hooks

minibuffer-exit-hook Variable
ミニバッファから抜けるたびに実行されるノーマルフック。 see Hooks

minibuffer-help-form Variable
この変数の現在値は、 ミニバッファの内側でhelp-formのローカルな束縛に使われる。 (see Help Functions)。

active-minibuffer-window Function
この関数は、現在活性なミニバッファのウィンドウを返す。 あるいは、活性なミニバッファがなければnilを返す。

minibuffer-window &optional frame Function
この関数は、フレームframeで使われるミニバッファ用ウィンドウを返す。 framenilであると、カレントフレームを意味する。 フレームで使うミニバッファ用ウィンドウは、 そのフレームの一部である必要はない。 ミニバッファを持たないフレームでは、 他のフレームのミニバッファ用ウィンドウを使う。

window-minibuffer-p window Function
この関数は、windowがミニバッファ用ウィンドウであると nil以外を返す。

与えられたウィンドウがミニバッファ用であるかどうかを調べるために、 (minibuffer-window)の戻り値と比較するのは正しくありません。 というのは、フレームが複数個あると 複数のミニバッファ用ウィンドウがあるからです。

minibuffer-window-active-p window Function
この関数は、ミニバッファ用ウィンドウwindowが活性であると nil以外を返す。

minibuffer-scroll-window Variable
この変数の値がnil以外であると、 値はウィンドウオブジェクトであること。 ミニバッファで関数scroll-other-windowが呼ばれると、 scroll-other-windowはこのウィンドウをスクロールする。

最後に、再帰ミニバッファ(see Recursive Editing)を扱う 関数と変数について述べます。

minibuffer-depth Function
この関数は、活性なミニバッファの現在の深さを非負整数で返す。 活性なミニバッファがなければ0を返す。

enable-recursive-minibuffers User Option
この変数がnil以外であると、 ミニバッファ用ウィンドウが活性であっても、 (find-fileなどの)ミニバッファを使うコマンドを起動できる。 そのような起動では、新たなミニバッファに対する再帰編集レベルが作られる。 内側の(深い)ミニバッファを編集中には、 外側の(浅い)レベルのミニバッファは見えない。

この変数がnilであると、 ミニバッファ用ウィンドウが活性なときには、 別のウィンドウに切り替えたとしてもミニバッファコマンドは使えない。

コマンド名にnil以外の 属性enable-recursive-minibuffersがあると、 当該コマンドをミニバッファから起動したときでさえ、 当該コマンドはミニバッファを使って引数を読み取れます。 ミニバッファコマンドnext-matching-history-element (ミニバッファでは通常M-s)は、この機能を使っています。


Node:Command Loop, Next:, Previous:Minibuffers, Up:Top

コマンドループ

読者がEmacsを起動すると、Emacsはほぼただちにエディタコマンドループ (editor command loop)に入ります。 このループは、キー列を読み取り、それらの定義を実行し、結果を表示します。 本章では、これがどのように行われるのか、および、 Lispプログラムからこれを行うためのサブルーティンについて述べます。


Node:Command Overview, Next:, Up:Command Loop

コマンドループの概要

コマンドループがまず始めに行うことはキー列、 つまり、コマンドへ変換されるイベント列を読むことです。 これには関数read-key-sequenceを呼び出します。 読者のLispコードでもこの関数を呼び出せます(see Key Sequence Input)。 Lispプログラムでは、read-event(see Reading One Event)で 低レベルの入力を行ったり、 discard-input(see Event Input Misc)で 処理待ち中の入力を破棄できます。

キー列は現在活性なキーマップを介してコマンドに変換されます。 この処理方法についてはSee Key Lookup。 この結果は、キーボードマクロであるか、 対話的に呼び出し可能な関数であるはずです。 キーがM-xであると、別のコマンドの名前を読み取り、 そのコマンドを呼び出します。 これはコマンドexecute-extended-command(see Interactive Call)で 処理されます。

コマンドを実行するには、まず、その引数を読む必要があります。 これは、command-execute(see Interactive Call)を呼び出して 行います。 Lispで書かれたコマンドでは、 interactive指定が引数の読み方を指示します。 前置引数(see Prefix Command Arguments)を使ったり、 プロンプトを表示してミニバッファ(see Minibuffers)から読みます。 たとえば、コマンドfind-fileには、 ミニバッファからファイル名を読むことを指示した interactive指定があります。 コマンドの関数本体ではミニバッファを使いません。 このコマンドをLispコードから関数として呼び出す場合、 通常のLisp関数の引数としてファイル名文字列を指定する必要があります。

コマンドが文字列やベクトル(つまり、キーボードマクロ)である場合、 execute-kbd-macroを用いてそれらを実行します。 読者自身がこの関数を呼び出してもかまいません(see Keyboard Macros)。

動作中のコマンドの実行を止めるには、C-gを打ちます。 この文字は中断(quitting)を引き起こします(see Quitting)。

pre-command-hook Variable
エディタコマンドループは、各コマンドのまえにこのノーマルフックを実行する。 その際、this-commandにはこれから実行するコマンドが保持され、 last-commandには直前のコマンドがある。 see Hooks

post-command-hook Variable
エディタコマンドループは、 (中断やエラーのために完了しなかったコマンドを含めて) 各コマンドのあとにこのノーマルフックを実行する。 初めてコマンドループに入ったときにも実行する。 その際、this-commandには実行し終えたばかりのコマンドがあり、 last-commandにはその前のコマンドがある。 see Hooks

pre-command-hookpost-command-hookの実行中は、 中断を禁止します。 これらのフックの1つを実行中にエラーが起きると、 エラーの無限ループを防ぐために、 フックの実行を終了しフック変数をnilにします。


Node:Defining Commands, Next:, Previous:Command Overview, Up:Command Loop

コマンドの定義

Lisp関数の本体に、スペシャルフォームinteractiveを呼び出す フォームがトップレベルにあると、Lisp関数はコマンドになります。 このフォームは実際に呼び出されてもなにもしませんが、 このフォームがあることで、対話的に呼び出せることを表します。 その引数が、対話的呼び出しにおける引数の読み方を制御します。


Node:Using Interactive, Next:, Up:Defining Commands

interactiveの使い方

本節では、Lisp関数を対話的に呼び出し可能なコマンドにするフォーム interactiveの書き方について述べます。

interactive arg-descriptor Special Form
このスペシャルフォームは、これを含む関数がコマンドであり、 (M-xや当該関数にバインドしたキー列を入力することで) 対話的に呼び出せることを宣言する。 引数arg-descriptorは、コマンドを対話的に呼び出したときに コマンドに対する引数の計算方法を宣言する。

他の関数と同様に、コマンドはLispプログラムからも呼び出せるが、 その場合、呼び出し側が引数を渡し、arg-descriptorにはなんの効果もない。

フォームinteractiveが効果を発揮するのは、 コマンドループ(実際にはサブルーティンcall-interactively)が 関数を呼び出すまえに関数定義を走査してこのフォームを探すからである。 関数が呼び出されると、フォームinteractiveを含めて その本体のフォームが実行されるが、そのとき、 interactiveは引数を評価せずに単にnilを返す。

引数arg-descriptorには3つの可能性があります。


Node:Interactive Codes, Next:, Previous:Using Interactive, Up:Defining Commands

interactiveのコード文字

以下に述べるコード文字の説明では、 つぎに定義するいくつかのキーワードを含みます。

「補完」
補完を使える。 completing-readを使って引数を読むため、 <TAB>、<SPC>、<RET>は名前を補完する (see Completion)。 ?は補完候補のリストを表示する。
「既存」
既存オブジェクトの名前を必要とする。 不正な名前は受け付けない。 現在の入力が正しくないとミニバッファから抜けるコマンドは動作しない。
「デフォルト」
ミニバッファにユーザーがなにもテキストを入力しないときに 使われるなんらかのデフォルト値。 デフォルトはコード文字に依存する。
「入出力なし」
このコード文字は、入力をまったく読まずに引数を計算する。 したがって、プロンプト文字列を使わず、 読者が指定したプロンプト文字列は無視する。

コード文字はプロンプト文字列を使わないが、 この文字が文字列の最後の文字でない場合には改行を続けること。

「プロンプト」
コード文字の直後にプロンプトが続く。 プロンプトは文字列の終りか改行で終る。
「スペシャル」
このコード文字は、対話指定文字列の先頭でのみ意味を持ち、 プロンプトや改行を必要としない。 これは1つの孤立した文字である。

以下に、interactiveに使うコード文字を説明します。

*
カレントバッファが読み出し専用であるとエラーを通知する。 「スペシャル」。
@
このコマンドを起動したキー列の最初のマウスイベントが表すウィンドウを選択する。 「スペシャル」。
a
関数名(つまり、fboundpを満たすシンボル)。 「既存」、「補完」、「プロンプト」。
b
既存バッファの名前。 デフォルトでは、カレントバッファ(see Buffers)の名前を使う。 「既存」、「補完」、「デフォルト」、「プロンプト」。
B
バッファ名。 バッファが既存である必要はない。 デフォルトでは、カレントバッファ以外の最近使ったバッファの名前を使う。 「補完」、「デフォルト」、「プロンプト」。
c
文字。 カーソルはエコー領域には移動しない。 「プロンプト」。
C
コマンド名(つまり、commandpを満たすシンボル)。 「既存」、「補完」、「プロンプト」。
d
整数としてのポイント位置(see Point)。 「入出力なし」。
D
ディレクトリ名。 デフォルトは、カレントバッファのカレントデフォルトディレクトリ default-directory(see System Environment)。 「既存」、「補完」、「デフォルト」、「プロンプト」。
e
コマンドを起動したキー列の最初やつぎのマウスイベント。 より正確には、eはリストであるイベントを取得するので、 読者はリスト内のデータを調べられる。 see Input Events。 「入出力なし」。

1つのコマンドの対話指定で複数回eを使える。 コマンドを起動したキー列がn個のリストであるイベントである場合、 n番目のeは、n番目のそのようなイベントを与える。 eでは、 ファンクションキーやASCII文字などのリストでないイベントは数えない。

f
既存ファイルの名前(see File Names)。 デフォルトディレクトリはdefault-directory。 「既存」、「補完」、「デフォルト」、「プロンプト」。
F
ファイル名。 ファイルが既存である必要はない。 「補完」、「デフォルト」、「プロンプト」。
i
無関係な引数。 このコードは、引数の値につねにnilを与える。 「入出力なし」。
k
キー列(see Keymap Terminology)。 現在のキーマップにおいてコマンドがみつかる(あるいは未定義コマンド)まで イベントを読み続ける。 キー列引数は、文字列かベクトルとして表現される。 カーソルはエコー領域には移動しない。 「プロンプト」。

この種の入力は、describe-keyglobal-set-keyなどの コマンドで使われる。

K
キー列であり、読者がその定義を変更することを意図している。 これはkと同様に動作するが、 キー列の最後の入力イベントに対しては、 未定義キーを定義済みのものに変換するために(必要なときに)普通使われる 変換処理を抑制する。
m
整数としてのマーク位置。 「入出力なし」。
M
カレントバッファの入力方式を用いてミニバッファで読んだ任意のテキスト。 文字列として返す (see Input Methods)。 「プロンプト」。
n
ミニバッファで読んだ数。 入力が数でないと、ユーザーに再入力を促す。 もし前置引数があってもそれは使わない。 「プロンプト」。
N
数値前置引数。 前置引数がなければ、nで数を読む。 数を必要とする。 see Prefix Command Arguments。 「プロンプト」。
p
数値前置引数。 (このpは小文字。) 「入出力なし」。
P
生の前置引数。 (このPは大文字。) 「入出力なし」。
r
2つの数値引数としてのポイントとマーク。 小さいほうが先にくる。 これは、1つではなく2つの連続した引数を指定する唯一のコード文字。 「入出力なし」。
s
ミニバッファで読んだ任意のテキスト。 文字列として返す(see Text from Minibuffer)。 C-jか<RET>で入力を終える。 (これらの文字を入力に含めるにはC-qを使う。) 「プロンプト」。
S
ミニバッファで読んだ名前をインターンしたシンボル。 白文字で入力を終える。 (文字列に白文字を含めるにはC-qを使う。) (丸括弧や角括弧などの)通常はシンボルを終える他の文字は、 ここではシンボルを終端しない。 「プロンプト」。
v
ユーザーオプションと宣言された変数 (つまり、述語user-variable-pを満たす)。 see High-Level Completion。 「既存」、「補完」、「プロンプト」。
x
入力構文で表されたLispオブジェクト。 C-jか<RET>で終える。 オブジェクトは評価しない。 see Object from Minibuffer。 「プロンプト」。
X
xのようにLispフォームを読むが、評価しその値がコマンドの引数になる。 「プロンプト」。
z
コーディングシステム名(シンボル)。 ユーザーの入力が空であると、引数の値はnil。 see Coding Systems。 「補完」、「既存」、「プロンプト」。
Z
このコマンドに前置引数を指定した場合にのみ、 コーディングシステム名(シンボル)。 前置引数がないと、Zは引数の値にnilを与える。 「補完」、「既存」、「プロンプト」。


Node:Interactive Examples, Previous:Interactive Codes, Up:Defining Commands

interactiveの使用例

ここではinteractiveの例を示します。

(defun foo1 ()              ; foo1は引数なし
    (interactive)           ; 2単語分先へ進める
    (forward-word 2))
     => foo1

(defun foo2 (n)             ; foo2は1引数
    (interactive "p")       ; 数値前置引数
    (forward-word (* 2 n)))
     => foo2

(defun foo3 (n)             ; foo3は1引数
    (interactive "nCount:") ; ミニバッファで読む
    (forward-word (* 2 n)))
     => foo3

(defun three-b (b1 b2 b3)
  "Select three existing buffers.
Put them into three windows, selecting the last one."
    (interactive "bBuffer1:\nbBuffer2:\nbBuffer3:")
    (delete-other-windows)
    (split-window (selected-window) 8)
    (switch-to-buffer b1)
    (other-window 1)
    (split-window (selected-window) 8)
    (switch-to-buffer b2)
    (other-window 1)
    (switch-to-buffer b3))
     => three-b
(three-b "*scratch*" "declarations.texi" "*mail*")
     => nil


Node:Interactive Call, Next:, Previous:Defining Commands, Up:Command Loop

対話的呼び出し

コマンドループでは、キー列をコマンドへ変換し終えると、 関数command-executeを用いてそのコマンドを起動します。 コマンドが関数であれば、command-executeは引数を読み取り、 コマンドを呼び出すcall-interactivelyを呼びます。 読者自身がこれらの関数を呼び出してもかまいません。

commandp object Function
objectが対話的呼び出しに適していれば、 つまり、objectがコマンドであればtを返す。 さもなければnilを返す。

対話的呼び出しが可能なオブジェクトには、 (キーボードマクロとして扱われる)文字列やベクトル、 トップレベルでinteractiveを呼び出しているラムダ式、 そのようなラムダ式をコンパイルしたバイトコード関数オブジェクト、 対話的(autoloadの4番目の引数がnil以外) と宣言された自動ロードオブジェクト、 一部の基本関数が含まれる。

シンボルの関数定義がcommandpを満たせば、 シンボルもcommandpを満たす。

キーやキーマップはコマンドではない。 それらはコマンドを探すために使われる(see Keymaps)。

commandpの実用的な使用例については、 Accessing Documentationdocumentationを参照。

call-interactively command &optional record-flag keys Function
この関数は、対話的呼び出し可能な関数commandを その対話指定に従って引数を読み取り呼び出す。 commandが関数でなかったり、 対話的に呼び出せない(つまり、コマンドでない)場合には、 エラーを通知する。 キーボードマクロ(文字列やベクトル)はコマンドとみなすが、 それらは関数でないため、この関数はキーボードマクロを受け付けない。

record-flagnil以外であると、 コマンドとその引数を無条件にリストcommand-historyに追加する。 さもなければ、引数を読むために コマンドがミニバッファを使った場合にのみ追加する。 see Command History

もし引数keysを指定すると、コマンドがそれを起動したイベントを 問い合わせたときに与えるイベント列を指定する。

command-execute command &optional record-flag keys Function
この関数はcommandを実行する。 引数commandcommandpを満たすこと。 つまり、対話的呼び出し可能な関数かキーボードマクロであること。

commandが文字列やベクトルであると、 execute-kbd-macroで実行される。 関数であると、省略可能なrecord-flagとともに関数を call-interactivelyに渡す。

シンボルは、その関数定義を使って処理する。 autoloadで定義されたシンボルは、 対話的呼び出し可能な関数と宣言されていればコマンドとみなす。 そのような定義では、指定されたライブラリをロードしてから シンボルの定義を再検査して処理する。

もし引数keysを指定すると、コマンドがそれを起動したイベントを 問い合わせたときに与えるイベント列を指定する。

execute-extended-command prefix-argument コマンド
この関数はcompleting-read(see Completion)を使って ミニバッファでコマンド名を読む。 そしてcommand-executeを使って指定されたコマンドを実行する。 コマンドが返した値がexecute-extended-commandの値になる。

コマンドが前置引数を必要とする場合、prefix-argumentの値を受け取る。 execute-extended-commandが対話的に呼ばれた場合、 現在の生の前置引数がprefix-argumentとして使われ、 それが実行するコマンドへ渡される。

execute-extended-commandは通常M-xに定義付けられ、 そのため、プロンプトとして文字列M-x を使う。 (execute-extended-commandを起動するために使われた イベントをプロンプトにするべきであるが、 それを実装するのは手間がかかる。) もし前置引数を指定すると、その内容もプロンプトの一部になる。

(execute-extended-command 1)
---------- Buffer: Minibuffer ----------
1 M-x forward-word RET
---------- Buffer: Minibuffer ----------
     => t

interactive-p Function
この関数は、これ(interactive-pの呼び出し)を含んだ関数が call-interactivelyで対話的に呼び出されるとtを返す。 (Lispからcall-interactivelyが呼び出されても、 エディタコマンドループが直接呼び出しても違いはない。) これを含んだ関数がLispの評価(あるいはapplyfuncall)で 呼び出された場合は、対話的呼び出しではない。

interactive-pのもっとも一般的な用途は、 情報メッセージを表示するかどうか決めることです。 特別な例外として、キーボードマクロを実行中にはいつでも、 interactive-pnilを返します。 これは情報メッセージを省いてマクロの実行を速くするためです。

つぎのように使います。

(defun foo ()
  (interactive)
  (when (interactive-p)
    (message "foo")))
     => foo

(defun bar ()
  (interactive)
  (setq foobar (list (foo) (interactive-p))))
     => bar

;; M-x fooと打つ
     -| foo

;; M-x barと打つ
;; これはなにも表示しない

foobar
     => (nil t)

この種のことを行う別の方法は、コマンドを 対話的呼び出しではnil以外の値になる引数print-messageを 取るようにし、その引数がnil以外になるようなinteractive指定を 使うことです。 つぎのようにします。

(defun foo (&optional print-message)
  (interactive "p")
  (when print-message
    (message "foo")))

pで与えられる数値前置引数はけっしてnilになりません。


Node:Command Loop Info, Next:, Previous:Interactive Call, Up:Command Loop

コマンドループからの情報

エディタコマンドループは、自身や実行中のコマンドのために 状態記録を数個のLisp変数に設定します。

last-command Variable
この変数は、コマンドループが(現在のコマンドの)まえに実行したコマンドの 名前を記録する。 通常、この値は関数定義を持つシンボルであるが、保証はしない。

コマンドが後続のコマンドに対する前置引数を指定する場合を除いて、 コマンドからコマンドループへ戻るとthis-commandから値をコピーする。

この変数は現在の端末に対してつねにローカルであり、 バッファに対してローカルにはならない。 see Multiple Displays

real-last-command Variable
last-commandと同様にEmacsがこの変数に設定するが、 Lispプログラムではけっして変更しない。

this-command Variable
この変数は、エディタコマンドループが いま実行しているコマンドの名前を記録する。 last-commandと同様に、通常は関数定義を持つシンボルである。

コマンドループは、コマンドを実行する直前にこの変数に設定し、 コマンドが終了すると(コマンドが後続のコマンドに対する 前置引数を指定する場合を除いて) この値をlast-commandにコピーする。

後続のコマンドに対するフラグとして 実行中にこの変数に設定するコマンドもある。 特に、テキストをキルする関数群はthis-commandkill-regionを 設定して、直後に続くキルコマンドでは キルしたテキストをまえのキルに追加するようにする。

特定のコマンドがエラーを起こした場合に 直前のコマンドとは認識されたくない場合には、 読者はそのコマンドがそれを防ぐように書く必要があります。 1つの方法は、以下に示すように、 コマンドの始めでthis-commandtを設定し、 コマンドの終りでthis-commandに正しい値を戻します。

(defun foo (args...)
  (interactive ...)
  (let ((old-this-command this-command))
    (setq this-command t)
    ...do the work...
    (setq this-command old-this-command)))

letthis-commandを束縛しません。 というのは、エラーがあるとletは古い値を復元するからです。 これこそがここでは避けたいletの機能です。

this-command-keys Function
この関数は、現在のコマンドに対して直前のコマンドが生成した前置引数を含めて、 現在のコマンドを起動したキー列を含んだ文字列かベクトルを返す。 すべてのイベントが文字であれば、値は文字列である。 see Input Events
(this-command-keys)
;; C-u C-x C-eを使ってこの式を評価する
     => "^U^X^E"

this-command-keys-vector Function
this-command-keysと同様だが、つねにベクトルでイベントを返すため、 文字列に入力イベントを保持する際の複雑さを扱う必要がない (see Strings of Events)。

last-nonmenu-event Variable
この変数は、マウスメニューによるイベントを考慮せずに、 キー列として読んだ最後の入力イベントを保持する。

この変数の1つの用途は、 メニューをポップアップする位置をx-popup-menuに指示することである。 y-or-n-p(see Yes-or-No Queries)も内部的に使っている。

last-command-event Variable
last-command-char Variable
この変数には、コマンドの一部としてコマンドループが 読んだ最後の入力イベントが設定される。 この変数の主な用途は、どの文字を挿入すべきかを決定するために self-insert-commandが使うことである。
last-command-event
;; C-u C-x C-eを使ってこの式を評価する
     => 5

C-eASCIIコードは5なので、値は5である。

Emacs 18版との互換性のために別名last-command-charがある。

last-event-frame Variable
この変数は、最後の入力イベントを振り向けたフレームを記録する。 通常これは、イベントが生成されたときに選択されていたフレームであるが、 そのフレームが入力フォーカスを別のフレームに振り向けていると、 この値はイベントを振り向けた先のフレームである。 see Input Focus


Node:Input Events, Next:, Previous:Command Loop Info, Up:Command Loop

入力イベント

Emacsのコマンドループは、キーボードやマウスのユーザーの操作を表す 入力イベント(input event)列を読みます。 キーボード操作に対するイベントは、文字かシンボルです。 マウスイベントはつねにリストです。 本節では、入力イベントの表現方法やその意味を詳しく説明します。

eventp object Function
この関数は、objectが入力イベントであるかイベント型であると nil以外を返す。

任意のシンボルがイベントやイベント型として使われることに注意。 eventpは、Lispのプログラムコードがシンボルを イベントとして使うかどうか区別できない。 そのかわりに、シンボルが、Emacsの現在のセッションにおいて入力として読まれた イベントに使われたことがあるかどうかを区別する。 シンボルがそのように使われたことがなければ、 eventpnilを返す。


Node:Keyboard Events, Next:, Up:Input Events

キーボードイベント

キーボードからは2種類の入力があります。 普通のキーとファンクションキーです。 普通のキーは文字に対応します。 それらが生成するイベントは、Lispでは文字として表現されます。 文字イベントのイベント型は文字自身(整数)です。 Classifying Eventsを参照してください。

入力文字イベントは、0から524287までの基本コード(basic code)と 以下の修飾ビット(modifier bit)の任意の組み合わせです。

meta
文字コードのビット は、メタキーを押し下げながら文字を打ったことを表す。
control
文字コードのビット は非ASCII文字のコントロール文字を表す。

C-aなどのASCIIコントロール文字には 独自の特別な基本コードがあるため、 Emacsはそれを表すための特別なビットを必要としない。 つまり、C-aのコードは単に1である。

しかし、コントロールキーを使った%などの ASCIIにないコントロールとの組み合わせを打った場合、 得られる数値は%のコードに を加えたものである (端末で非ASCIIのコントロール文字を扱えるとして)。

shift
文字コードのビット は、シフトキーを押し下げながら ASCIIコントロール文字を打ったことを表す。

英文字では、基本コードそのものが大文字か小文字かを表す。 数字文字と区切り文字では、 シフトキーは異なる基本コードのまったく異なる文字を選ぶ。 可能な限りASCII文字集合ですませるために、 これらの文字に対しては、Emacsはビット を使わない。

しかし、ASCIIではC-AC-aを区別できないため、 Emacsは、C-Aではビット を使うが、C-aではこのビットを使わない。

hyper
文字コードのビット は、ハイパーキーを押し下げながら文字を打ったことを表す。
super
文字コードのビット は、スーパーキーを押し下げながら文字を打ったことを表す。
alt
文字コードのビット は、アルトキーを押し下げながら文字を打ったことを表す。 (<ALT>とラベルされたキーが実際にはメタキーである端末も存在する。)

読者のプログラム内では、 特定の修飾ビットの値を明示することは避けるのが最良です。 文字の修飾ビットを検査するには、 関数event-modifiers(see Classifying Events)を使います。 キーバインディングを作るときには、 (\C-\M-などの)修飾ビットを伴う文字の 入力表現を使います。 define-keyでキーバインディングを作るときには、 文字の指定には(control hyper ?x)のようなリストを使います (see Changing Key Bindings)。 関数event-convert-listは、そのようなリストを イベント型に変換します(see Classifying Events)。


Node:Function Keys, Next:, Previous:Keyboard Events, Up:Input Events

ファンクションキー

ほとんどのキーボードには、ファンクションキー(function key)、 つまり、文字ではない名前や記号のキーがあります。 Emacs Lispでは、ファンクションキーはシンボルで表現されます。 シンボルの(小文字の)名前がファンクションキーのラベルです。 たとえば、<F1>というラベルのキーを押すと、 入力ストリームにはシンボルf1が置かれます。

ファンクションキーイベントのイベント型は、イベントシンボルそれ自身です。 See Classifying Events

ファンクションキーに対するシンボル命名慣習の特例を以下に示します。

backspace, tab, newline, return, delete
これらのキーは、ほとんどのキーボードにある特別なキーを持つ 一般的なASCIIコントロール文字に対応する。

ASCIIでは、C-iと<TAB>は同じ文字である。 これらを区別できる端末では、前者を整数9、後者をシンボルtabと 表現することで、EmacsはLispプログラムに区別を伝える。

ほとんどの場面では、これら2つを区別しても有用ではない。 そのため、通常、function-key-map(see Translating Input)は、 tabを9に対応付けるようには設定してある。 したがって、文字コード9(文字C-i)に対するキーバインディングは tabにも適用される。 この種の他のシンボルについても同様である。 関数read-charも同様にこれらのイベントを文字に変換する。

ASCIIでは、<BS>は実際にはC-hである。 しかし、backspaceは文字コード127(<DEL>)に変換され、 文字コード8(<BS>)には変換されない。 ほとんどのユーザーはこれを好む。

left, up, right, down
カーソル矢印キー
kp-add, kp-decimal, kp-divide, ...
(普通のキーボードの右側にある)キーパッドのキー。
kp-0, kp-1, ...
キーパッドの数字キー。
kp-f1, kp-f2, kp-f3, kp-f4
キーパッドのPFキー
kp-home, kp-left, kp-up, kp-right, kp-down
キーパッドの矢印キー。 Emacsは、通常、これらを対応するキーパッドのものではない homeleft...のキーに変換する。
kp-prior, kp-next, kp-end, kp-begin, kp-insert, kp-delete
普通のキーに対応するキーパッドのキー。 Emacsは、通常、同じ名前のキーパッドのものではないキーに変換する。

ファンクションキーにも<ALT>、<CTRL>、<HYPER>、 <META>、<SHIFT>、<SUPER>の修飾キーを使えます。 それらを表現するには、シンボル名に接頭辞を付けます。

A-
アルト修飾。
C-
コントロール修飾。
H-
ハイパー修飾。
M-
メタ修飾。
S-
シフト修飾。
s-
スーパー修飾。

したがって、<META>を押し下げた<F3>キーのシンボルはM-f3です。 複数の接頭辞を使うときには、アルファベット順に書くことを勧めますが、 キーバインディングの探索関数や修飾関数の引数では関係ありません。


Node:Mouse Events, Next:, Previous:Function Keys, Up:Input Events

マウスイベント

Emacsでは4種類のマウスイベント、つまり、クリックイベント、ドラッグイベント、 ボタン押し下げイベント、モーションイベントを扱えます。 すべてのマウスイベントは、リストで表現します。 リストのCARはイベント型であり、 どの修飾キーとともにどのマウスボタンを使ったかを表します。 イベント型では、ダブル(連続2回)/トリプル(連続3回)の 押し下げも区別できます(see Repeat Events)。 リストの残りの要素は、位置情報と時間情報です。

キーの探索では、イベント型のみが意味を持ちます。 型が同じであれば、異なるイベントでも同じコマンドを実行します。 コマンドでは、対話指定コードeを用いてイベントの完全な値を参照できます。 See Interactive Codes

マウスイベントで始まるキー列は、カレントバッファのキーマップではなく、 マウスが入っているウィンドウのバッファのキーマップを用いて読まれます。 つまり、あるウィンドウ内でクリックしても、 当該ウィンドウやバッファを選択するとは限らず、 その動作はキー列のコマンドバインディングで完全に制御されます。


Node:Click Events, Next:, Previous:Mouse Events, Up:Input Events

クリックイベント

ユーザーがマウスのボタンを同じ場所で押し下げてから離すと、 クリック(click)イベントが生成されます。 マウスクリックイベントはつぎの形式です。

(event-type
 (window buffer-pos (x . y) timestamp)
 click-count)

通常の各要素の意味はつぎのとおりです。

event-type
どのマウスボタンが使われたかを表すシンボル。 ボタンを左から右へ番号を付けて、 シンボルmouse-1mouse-2...の1つである。

ファンクションキーの場合と同様に、 アルト、コントロール、ハイパー、メタ、シフト、スーパーの 修飾キーを表す接頭辞A-C-H-M-S-s-も使える。

このシンボルはイベントのイベント型としての役割も果たす。 キーバインディングはイベント型でイベントを指定する。 したがって、mouse-1に対するキーバインディングは、 イベント型event-typemouse-1であるすべてのイベントに適用される。

window
クリックを行ったウィンドウ。
x, y
ウィンドウwindowの左上端を(0 . 0)とした クリック位置のピクセル単位の座標。
buffer-pos
クリックした文字のバッファ内位置。
timestamp
イベントが発生したときのミリ秒単位の時刻。 (この値は、Emacs Lispの整数の範囲では約5時間で一周するので、 時間的に近傍のイベントを関連付ける場合にのみ有用である。)
click-count
同じマウスボタンを素早く押し下げた繰り返し回数。 see Repeat Events

モード行やスクロールバーなどのスクリーンの特別な部分で発生したイベントでは、 buffer-posxyの意味は少々異なります。

スクロールバーの内側でのクリックでは、 buffer-posはシンボルvertical-scroll-barhorizontal-scroll-barであり、 (x . y)(portion . whole)に 置き換えられます。 ここで、portionはスクロールバーの先頭や左端からのクリック位置、 wholeはスクロールバー全体の長さです。

モード行やウィンドウwindowを右隣のものと区切る 縦方向の区切り行の内側では、 buffer-posはシンボルmode-linevertical-lineです。 モード行では、yは意味のあるデータではありません。 縦方向の区切り行では、xは意味のあるデータではありません。

1つの特別な場面では、 buffer-posは単一のシンボルではなく(上に述べた1つの)シンボルを 含んだリストになります。 イベントに対する仮想的なプレフィックスキーを入力ストリームに挿入すると このようになります。 See Key Sequence Input


Node:Drag Events, Next:, Previous:Click Events, Up:Input Events

ドラッグイベント

Emacsには、ドラッグイベントがあります。 ユーザーがマウスボタンを押し下げてから、 ボタンを離すまえに別の文字位置へマウスを動かすと ドラッグ(drag)イベントが発生します。 マウスのすべてのイベントのように、Lispではドラッグイベントは リストとして表現されます。 つぎのように、リストは開始マウス位置と終了位置を記録しています。

(event-type
 (window1 buffer-pos1 (x1 . y1) timestamp1)
 (window2 buffer-pos2 (x2 . y2) timestamp2)
 click-count)

ドラッグイベントでは、シンボルevent-typeの名前には 接頭辞drag-が付きます。 たとえば、ボタン2を押し下げてマウスをドラッグすると イベントdrag-mouse-2が生成されます。 イベントの2番目と3番目の要素は、ドラッグの開始位置と終了位置を与えます。 なお、データにはクリックイベントと同じ意味があります(see Click Events)。 ドラッグイベントかどうかを区別せずに、 マウスの任意のイベントの2番目の要素は同じ方法で参照できます。

接頭辞drag-は、 C-M-のような修飾キー接頭辞に続きます。

read-key-sequenceが、 キーバインディングを持たないドラッグイベントを受け取り、かつ、 それに対応するクリックイベントにはバインディングがある場合、 ドラッグイベントの開始位置をクリック位置とするクリックイベントに変換します。 つまり、望まなければ、読者はクリックイベントとドラッグイベントを区別する 必要がありません。


Node:Button-Down Events, Next:, Previous:Drag Events, Up:Input Events

ボタン押し下げイベント

クリックイベントとドラッグイベントは、 ユーザーがマウスボタンを離したときに発生します。 ボタンを離すまではクリックとドラッグを区別する方法がないため、 ボタンを離すまで発生しえません。

ボタンを押し下げたらただちに動作を始めたい場合には、 読者はボタン押し下げ(button-down)イベントを処理する必要があります。 8 ボタンを押し下げるとただちに発生します。 それらは、シンボルevent-typeの名前に 接頭辞down-があることを除けば、 クリックイベント(see Click Events)とまったく同じリストで表現されます。 接頭辞down-は、C-M-のような修飾キー接頭辞に続きます。

関数read-key-sequenceは、 コマンドバインディングを持たないボタン押し下げイベントを無視します。 したがって、Emacsのコマンドループもそれらを無視します。 つまり、読者がボタン押し下げイベントでなにかをしたいのでなければ、 読者はボタン押し下げイベントを定義する必要はありません。 ボタン押し下げイベントを定義する理由は、 ボタンが離されるまで(モーションイベントを読んで)マウスの動きを 追跡するためです。 See Motion Events


Node:Repeat Events, Next:, Previous:Button-Down Events, Up:Input Events

繰り返しイベント

マウスを動かさずに同一のマウスボタンを素早く連続して押し下げると、 Emacsは2回目以降の押し下げに対して 特別な繰り返し(repeat)マウスイベントを生成します。

もっとも一般的な繰り返しイベントはダブルクリック(double-click) イベントです。 ボタンを2回クリックすると、Emcasはダブルクリックイベントを生成します。 (他のすべてのクリックイベントのように)読者がボタンを離したときに イベントが生成されます。

ダブルクリックイベントのイベント型には、接頭辞double-が含まれます。 したがって、<meta>を押し下げて2番目のボタンをダブルクリックすると、 LispプログラムにはM-double-mouse-2が送られます。 ダブルクリックイベントにバインディングがなければ、 対応する普通のクリックイベントを用いて実行します。 したがって、実際に利用したくない限りは、 読者はダブルクリック機能に注意する必要はありません。

ユーザーがダブルクリックすると、Emacsはまず普通のクリックイベントを生成し、 つぎにダブルクリックイベントを生成します。 したがって、ダブルクリックイベントのコマンドバインディングでは、 すでに普通のクリックコマンドが動作済みであると仮定して設計する必要があります。 普通のクリックの結果をもとに望みのダブルクリックの結果を得るようにします。

普通のクリックの意味にダブルクリックの意味を 『追加』するようにすると便利です。 ダブルクリックのユーザーインターフェイスはこのようにすることを勧めます。

ボタンをクリックして、ふたたびボタンを押し下げてそのままマウスを動かすと、 最終的にボタンを離した時点で、ダブルドラッグ(double-drag)イベントが 生成されます。 そのイベント型にはdragのかわりにdouble-dragが含まれます。 ダブルドラッグイベントにバインディングがなければ、 Emacsは普通のドラッグイベントとしてバインディングを探します。

ダブルクリックイベントやダブルドラッグイベントを生成するまえに、 ユーザーがボタンを2回目に押し下げたとき、 Emacsはダブルダウン(double-down)イベントを生成します。 このイベント型にはdownのかわりにdouble-downが含まれます。 ダブルダウンイベントにバインディングがなければ、 Emacsは普通のボタン押し下げイベントとしてバインディングを探します。 どちらでもバインディングがみつからなければ、ダブルダウンイベントは無視します。

まとめると、ボタンをクリックしてただちに再度ボタンを押し下げると、 Emacsは、はじめのクリックに対してボタン押し下げイベントと クリックイベントを生成し、 再度ボタンを押し下げるとダブルダウンイベントを生成し、 最後にダブルクリックイベントかダブルドラッグイベントを生成します。

ボタンを2回クリックしてから再度押し下げる操作を素早く行うと、 Emacsは、トリプルダウン(triple-down)イベントに続けて トリプルクリック(triple-click)イベントか トリプルドラッグ(triple-drag)イベントを生成します。 これらのイベント型にはdoubleのかわりにtripleが含まれます。 トリプルのイベントにバインディングがなければ、 Emacsは対応するダブルのイベントを使います。

ボタンを3回以上クリックしてから再度押し下げると、 3回目以降の押し下げに対するイベントはすべてトリプルのイベントです。 Emacsは、クアドラプル(4回)、クインタプル(5回)、…などの イベントは生成しません。 しかし、イベントリストを調べれば、ボタンを何回押したか正確にわかります。

event-click-count event Function
この関数は、イベントeventにおいてボタンが連続して押された回数を返す。 eventが、ダブルダウンイベント、ダブルクリックイベント、 ダブルドラッグイベントであると、値は2である。 eventがトリプルのイベントであると、値は3かそれ以上である。 eventが(繰り返しイベントではない)普通のマウスイベントであると、 値は1である。

double-click-time Variable
繰り返しイベントが生成されるためには、 同じスクリーン位置において連続してマウスボタンを押し下げ、しかも、 各押し下げの間隔はdouble-click-timeの値未満(ミリ秒)である必要がある。 double-click-timenilを設定すると、 連続したクリックの検出を禁止する。 tを設定すると時間制限をなくし、 Emacsは連続したクリックの検出を位置だけで行う。


Node:Motion Events, Next:, Previous:Repeat Events, Up:Input Events

モーションイベント

Emacsは、ボタン操作を伴わないマウスの移動を表す マウスモーション(mouse motion)イベントを生成することがあります。 マウスモーションイベントはつぎのようなリストで表現されます。

(mouse-movement (window buffer-pos (x . y) timestamp))

リストの2番目の要素は、クリックイベント(see Click Events)と同様に、 マウスの現在位置を表します。

スペシャルフォームtrack-mouseにより、 その本体の内側ではモーションイベントの生成を可能にできます。 フォームtrack-mouseの外側では、 Emacsはマウスの移動のみに対するイベントを生成しないので、 それらのイベントは現れません。 See Mouse Tracking


Node:Focus Events, Next:, Previous:Motion Events, Up:Input Events

フォーカスイベント

ウィンドウシステムは、どのウィンドウにキーボード入力を与えるかを ユーザーが制御するための一般的な方法を提供します。 ウィンドウを選ぶことをフォーカス(focus)と呼びます。 ユーザーがEmacsのフレームを切り替える操作を行うと、 フォーカスイベント(focus event)が生成されます。 グローバルキーマップにあるフォーカスイベントの普通の定義は、 Emcasの新たなフレームを選択するようになっていて、 これはユーザーが期待することです。 See Input Focus

Lispでは、フォーカスイベントはつぎのようなリストで表現されます。

(switch-frame new-frame)

ここで、new-frameは切り替え先のフレームです。

Xのほとんどのウィンドウマネージャは、 マウスをウィンドウへ入れるだけで当該ウィンドウにフォーカスが設定される ようになっています。 フレームにマウスが入るとカーソルの形状を変更するので、 Emacsでもそのようにします。 しかし、Lispプログラムにとっては、 なんらかの入力が到着するまではフォーカスの変更について知る必要がありません。 そのため、ユーザーが実際にキーボードのキーを打つか 新たなフレームでマウスボタンを押し下げたときだけ、 Emacsはフォーカスイベントを生成します。 フレーム間でマウスを動かしただけでは、フォーカスイベントは生成されません。

キー列の途中にフォーカスイベントが現れると、キー列を乱します。 そのため、Emacsはキー列の途中にはフォーカスイベントを生成しません。 ユーザーがキー列の途中で、つまり、 プレフィックスキーのあとでフォーカスを変更すると、 複数イベントのキー列のまえかうしろにフォーカスイベントを移動し、 途中には現れないようにEmacsはイベントの順序を並び替えます。


Node:Misc Events, Next:, Previous:Focus Events, Up:Input Events

ウィンドウシステムのその他のイベント

ウィンドウシステム内で起きたことを表す他のイベントもあります。

(delete-frame (frame))
この種のイベントは、 Emacsのフレームであるウィンドウを削除するコマンドを ユーザーがウィンドウマネージャに与えたことを表す。

イベントdelete-frameの標準定義はフレームframeの削除である。

(iconify-frame (frame))
この種のイベントは、 ウィンドウマネージャを用いてユーザーがフレームframeを アイコン化したことを表す。 これに対する標準定義はignoreである。 というのは、フレームはすでにアイコンになっているので、 Emacsが行うことはなにもないからである。 このイベント型の目的は、 必要ならばその種のイベントを読者が追跡できるようにしておくことである。
(make-frame-visible (frame))
この種のイベントは、 ウィンドウマネージャを用いてユーザーがアイコン化したフレームframeを 開いたことを表す。 これに対する標準定義はignoreである。 というのは、フレームはすでに見えるようになっているので、 Emacsが行うことはなにもないからである。
(mouse-wheel position delta)
この種のイベントは、 (MSインテリマウスなどの)マウスのホイールを動かすと生成される。 その典型的な効果はスクロールやズーミングである。

要素deltaはホイールの回転方向と回転量である。 その絶対値はホイールを回すごとに増加する数である。 負のdeltaは、逆転、つまり、ユーザーへ近付く方向への回転を表し、 正のdeltaは、順転、つまり、ユーザーから遠ざかる方向への回転を表す。

要素positionはイベントの発生位置を表し、 マウスクリックイベントで使われる形式と同じである。

この種のイベントは、ある種のシステムでのみ生成される。

(drag-n-drop position files)
この種のイベントは、 Emacsの外側のアプリケーションで一群のファイルを選択し、 それらをEmacsのフレームにドラッグ&ドロップしたときに生成される。

要素positionはイベントの発生位置を表し、 マウスクリックイベントで使われる形式と同じであり、 要素filesはドラッグ&ドロップされたファイル名のリストである。 このイベントを扱う通常の処理は、それらのファイルを訪問することである。

現状では、この種のイベントは、ある種のシステムでのみ生成される。

これらのイベントがキー列の途中、つまり、 プレフィックスキーのうしろに現れると、 複数イベントのキー列のまえかうしろに当該イベントを移動し、 途中には現れないようにEmacsはイベントの順序を並び替えます。


Node:Event Examples, Next:, Previous:Misc Events, Up:Input Events

イベントの例

ユーザーが同じ場所でマウスの左ボタンを押し下げてから離すと、 つぎのようなイベント列が生成されます。

(down-mouse-1 (#<window 18 on NEWS> 2613 (0 . 38) -864320))
(mouse-1      (#<window 18 on NEWS> 2613 (0 . 38) -864180))

コントロールキーを押し下げた状態で、 ユーザーがマウスの2番目のボタンを押し下げ、 マウスをつぎの行へドラッグすると、つぎのような2つのイベントが生成されます。

(C-down-mouse-2 (#<window 18 on NEWS> 3440 (0 . 27) -731219))
(C-drag-mouse-2 (#<window 18 on NEWS> 3440 (0 . 27) -731219)
                (#<window 18 on NEWS> 3510 (0 . 28) -729648))

メタキーとシフトキーを押し下げた状態で、 ユーザーがマウスの2番目のボタンをウィンドウのモード行で押し下げ、 マウスを別のウィンドウへドラッグすると、 つぎのような2つのイベントが生成されます。

(M-S-down-mouse-2 (#<window 18 on NEWS> mode-line (33 . 31) -457844))
(M-S-drag-mouse-2 (#<window 18 on NEWS> mode-line (33 . 31) -457844)
                  (#<window 20 on carlton-sanskrit.tex> 161 (33 . 3)
                   -453816))


Node:Classifying Events, Next:, Previous:Event Examples, Up:Input Events

イベントの分類

各イベントにはイベント型(event type)があって、 キーバインディング処理のためにイベントを分類します。 キーボードイベントでは、イベント型はイベントの値に等しいです。 したがって、文字に対するイベント型は文字であり、 ファンクションキーに対するイベント型はシンボルそのものです。 リストであるイベントでは、イベント型はリストのCARにあるシンボルです。 したがって、イベント型はつねにシンボルか文字です。

イベント型が同じであるイベントは、キーバインディングに関する限り同じです。 つまり、それらは同じコマンドを実行します。 しかし、これは、それらが必ずしも同じことを行うという意味ではありません。 イベント全体を調べてなにを行うかを決定するコマンドもあります。 たとえば、マウスイベントの生起位置を使って、 バッファのどの部分を処理するかを決めるコマンドもあります。

イベントをおおまかに分類すると有用な場合もあります。 たとえば、他の修飾キーやマウスボタンには関係なしに、 <META>キーが使われているイベントかどうか調べたいことがあるでしょう。

関数event-modifiersevent-basic-typeは、 そのような情報を便利に与えるためのものです。

event-modifiers event Function
この関数は、eventにある修飾子のリストを返す。 修飾子はシンボルであり、shiftcontrolmetaalthypersuperである。 さらに、マウスイベントシンボルの修飾子リストには、 必ず、clickdragdownの1つが含まれる。

引数eventは、イベントオブジェクト全体であるか、単なるイベント型である。

例を示す。

(event-modifiers ?a)
     => nil
(event-modifiers ?\C-a)
     => (control)
(event-modifiers ?\C-%)
     => (control)
(event-modifiers ?\C-\S-a)
     => (control shift)
(event-modifiers 'f5)
     => nil
(event-modifiers 's-f5)
     => (super)
(event-modifiers 'M-S-f5)
     => (meta shift)
(event-modifiers 'mouse-1)
     => (click)
(event-modifiers 'down-mouse-1)
     => (down)

クリックイベントに対する修飾子リストにはclickが明示的に含まれるが、 イベントシンボルの名前自体にはclickは含まれない。

event-basic-type event Function
この関数は、eventにあるキーやマウスボタンを返す。 たとえばつぎのとおり。
(event-basic-type ?a)
     => 97
(event-basic-type ?A)
     => 97
(event-basic-type ?\C-a)
     => 97
(event-basic-type ?\C-\S-a)
     => 97
(event-basic-type 'f5)
     => f5
(event-basic-type 's-f5)
     => f5
(event-basic-type 'M-S-f5)
     => f5
(event-basic-type 'down-mouse-1)
     => mouse-1

mouse-movement-p object Function
この関数は、objectがマウス移動のイベントならばnil以外を返す。

event-convert-list list Function
この関数は、修飾子名と基本イベント型のリストを それらが示すイベント型に変換する。 たとえばつぎのとおり。
(event-convert-list '(control ?a))
     => 1
(event-convert-list '(control meta ?a))
     => -134217727
(event-convert-list '(control super f1))
     => C-s-f1


Node:Accessing Events, Next:, Previous:Classifying Events, Up:Input Events

イベントの参照

本節では、マウスボタンイベントやモーションイベント内のデータを 参照するための便利な関数について述べます。

つぎの2つの関数は、以下の形式のリストであるマウスボタンイベントの 開始位置や終了位置を返します。

(window buffer-position (x . y) timestamp)

event-start event Function
イベントeventの開始位置を返す。

eventがクリックイベントやボタン押し下げイベントであると、 イベントの位置を返す。 eventがドラッグイベントであると、ドラッグの開始位置を返す。

event-end event Function
イベントeventの終了位置を返す。

eventがドラッグイベントであると、 ユーザーがマウスボタンを離したときの位置を返す。 eventがクリックイベントかボタン押し下げイベントであると、 実際の値は開始位置であり、 その種のイベントにある唯一の位置情報である。

つぎの5つの関数は、上に述べた位置情報のリストを引数として、 そのさまざまな部分を返す。

posn-window position Function
position内のウィンドウを返す。

posn-point position Function
positionのバッファ内位置を返す。 これは整数である。

posn-x-y position Function
position内のピクセル単位のxy座標を コンスセル(x . y)として返す。

posn-col-row position Function
positionの(文字単位の)行(row)とコラム(col)の座標を コンスセル(col . row)として返す。 これらは実際にはposition内のxyの値から計算される。

posn-timestamp position Function
position内の時刻情報を返す。

つぎの関数はスクロールバーでのイベントを解読するのに便利です。

scroll-bar-event-ratio event Function
スクロールバー内でのイベントから、スクロールバーに対する縦方向の位置を返す。 その値は2つの整数を含むコンスセル(portion . whole)であり、 その比は位置の割合を表す。

scroll-bar-scale ratio total Function
この関数は(実質的には)ratiototalを掛け、 結果を整数に丸める。 引数ratioは数ではなく(num . denom)であり、 典型的にはscroll-bar-event-ratioが返す値である。

この関数はスクロールバー内での位置を バッファ内での位置へ換算するのに便利である。 つぎのように行う。

(+ (point-min)
   (scroll-bar-scale
      (posn-x-y (event-start event))
      (- (point-max) (point-min))))

スクロールバー内でのイベントには、 xy座標のかわりに比を表す2つの整数があることに注意。


Node:Strings of Events, Previous:Accessing Events, Up:Input Events

キーボードイベントを文字列で保持する

文字列が使われるほとんどの場面では、 文字列にはテキスト文字、つまり、 バッファやファイルにある文字と同じ種類のものが入っていると考えています。 文字列にはキーボード文字が入っているとみなして使うLispプログラムもあります。 たとえば、文字列には、キー列やキーボードマクロの定義が入っているのです。 しかし、キーボード文字を文字列に保持するのは複雑であり、 それは歴史的な互換性を保つためにするのであり、 また、つねに可能とは限りません。

新しいプログラムでは、キーボードイベントを文字列に保持しないで、 このような複雑さを避けるように推奨します。 つぎのようにします。

複雑さの原因は、キーボード入力に含まれる修飾ビットにあります。 メタ修飾子以外の修飾ビットを文字列に入れることは不可能であり、 メタ修飾子は特別な場合として唯一許されているのです。

初期のGNU Emacsでは、メタ文字を128から255の範囲のコードで表現していました。 その当時、基本文字コードは0から127でしたから、 キーボード文字のすべてのコードは文字列に収まったのです。 多くのLispプログラムでメタ文字を表すために文字列定数内で\M-を使い、 特に、define-keyや類似の関数に対する引数に使われ、 キー列やイベント列はつねに文字列で表現されていました。

127を超える大きな基本文字コードと追加の修飾ビットを扱えるようにしたとき、 メタ文字の表現方法を変更せざるをえませんでした。 現在、メタ修飾子を表す文字内のビットは であり、そのような数を文字列に入れることはできません。

文字列定数で\M-を使っているプログラムを扱えるように、 文字列にメタ文字を入れるための特別な規則があります。 以下は、文字列を入力文字の列として解釈するための規則です。

キーボード入力文字の文字列を作るread-key-sequenceなどの関数は つぎの規則に従います。 つまり、文字列に収まらないイベントであるときには、 文字列のかわりにベクトルを作ります。

読者が文字列で\M-の入力構文を使うと、 それらは128から255の範囲のコードになります。 対応するキーボードイベントを文字列に保存するように変更したときに得られる コードと同じです。 したがって、文字列内のメタイベントは、それらがどのように文字列に 収められたかに関わらず、整合性のある動作をします。

しかし、本節のはじめに述べた推奨方法に従ってこれらのことがらを避けるほうが、 ほとんどのプログラムはよりよく動作するでしょう。


Node:Reading Input, Next:, Previous:Input Events, Up:Command Loop

入力の読み取り

エディタコマンドループは、 関数read-key-sequenceを使ってキー列を読み取ります。 なお、関数read-key-sequenceは関数read-eventを使います。 これらやイベント入力を扱う他の関数は、Lispプログラムからも使えます。 Temporary Displaysmomentary-string-display、 および、Waitingsit-forを参照してください。 端末の入力モードの制御や端末入力のデバッグに関する関数や変数については、 See Terminal Input。 入力イベントを読むときにそれらを変換したり修正する機能については、 See Translating Input

上位レベルの入力機能については、Minibuffersを参照してください。


Node:Key Sequence Input, Next:, Up:Reading Input

キー列の入力

コマンドループは、read-key-sequenceを呼ぶことで キー列の入力を読み取ります。 Lispプログラムからこの関数を呼び出してもよく、 たとえば、describe-keyは、 説明対象とするキーを読むためにこの関数を使います。

read-key-sequence prompt Function
この関数は、キー列を読み取り文字列かベクトルとして返す。 完全なキー列を収集し終えるまで、 つまり、現在活性なキーマップにおいて、非プレフィックスコマンドを 指定するのに十分になるまで、イベントを読み続ける。

イベントがすべて文字であり、かつ、それらが文字列に収まるならば、 read-key-sequenceは文字列(see Strings of Events)を返す。 さもなければ、ベクトルを返す。 ベクトルならば、任意の種類のイベント、つまり、 文字、シンボル、リストを保持できるからである。 文字列やベクトルの要素は、キー列のイベントである。

引数promptは、プロンプトとしてエコー領域に表示する文字列であるか、 あるいは、プロンプトを表示しないことを意味するnilである。

以下の例では、プロンプト?がエコー領域に表示され、 ユーザーはC-x C-fと打つ。

(read-key-sequence "?")

---------- Echo Area ----------
?C-x C-f
---------- Echo Area ----------

     => "^X^F"

関数read-key-sequenceは中断を抑止する。 この関数が動作中にC-gを打っても、他の文字と同様に扱い、 quit-flagを設定しない。 see Quitting

read-key-sequence-vector prompt Function
これはread-key-sequenceと同様であるが、 つねにベクトルとしてキー列を返し、文字列としてはけっして返さない。 see Strings of Events

入力文字が大文字であって、それらにキーバインディングがないとき、 対応する小文字にキーバインディングがあれば、 read-key-sequenceは文字を小文字に変換します。 lookup-keyはこのような変換を行わないことに注意してください。

関数read-key-sequenceは、ある種のマウスイベントも変換します。 バインディングのないドラッグイベントをクリックイベントに変換したり、 バインディングのないボタン押し下げイベントを完全に無視します。 さらに、フォーカスイベントとその他のウィンドウイベントを並び替えて、 それらが他のイベントのキー列の途中に現れないようにします。

マウスイベントが、モード行やスクロールバーなどのウィンドウの特別な部分で 生起しても、特別なイベント型はなく、マウスボタンや修飾キーの 組み合わせを普通どおりに表したシンボルです。 ウィンドウのどの部分かに関する情報は、 イベント内の別の部分、つまり、座標に入っています。 しかし、read-key-sequenceは、その情報を シンボルmode-linevertical-linehorizontal-scroll-barvertical-scroll-barを用いた仮想的な『プレフィックスキー』に変換します。 ウィンドウの特別な部分におけるマウスクリックの意味は、 これらの仮想的なプレフィックスキーを用いてキー列を定義することで 定義できます。

たとえば、read-key-sequenceを呼び出してから、 ウィンドウのモード行でクリックすると、 つぎのような2つのイベントを得ます。

(read-key-sequence "Click on the mode line: ")
     => [mode-line
         (mouse-1
          (#<window 6 on NEWS> mode-line
           (40 . 63) 5959987))]

num-input-keys Variable
この変数の値は、現在のEmacsセッションにおいて、 これまでに処理されたキー列の個数である。 これには、端末から読み取ったキー列、および、 実行したキーボードマクロから読み取ったキー列が含まれる。

num-nonmacro-input-events Variable
この変数は、端末からこれまでに受け取った入力イベントの総個数を保持する。 キーボードマクロで生成されたものは含まない。


Node:Reading One Event, Next:, Previous:Key Sequence Input, Up:Reading Input

単一イベントの読み取り

コマンド入力用の最低レベルの関数は、単一イベントを読み取る関数です。

read-event &optional prompt suppress-input-method Function
この関数は、必要ならばイベントの到着を待って、 コマンド入力のつぎのイベントを読み取って返す。 イベントは、ユーザーか(実行中の)キーボードマクロから直接得る。

promptnil以外であると、 これはプロンプトとしてエコー領域に表示される文字列であること。 さもなければ、read-eventは 入力待ちであることを示すメッセージを表示せずに、 そのかわりに、現在のコマンドを実行するに至ったイベントや 現在のコマンドが読み取ったイベントをプロンプトとして表示する。 see The Echo Area

suppress-input-methodnil以外であると、 このイベントの読み取りに関しては現在の入力方式を使わない。 入力方式の処理をせずにイベントを読みたいときには、 つねにこのようにすること。 input-method-functionを束縛してはならない(下記参照)。

変数cursor-in-echo-areanil以外であると、 read-eventは、エコー領域に表示されたメッセージの末尾に カーソルを一時的に移動する。 さもなければ、read-eventはカーソルを移動しない。

read-eventがヘルプ文字と定義されたイベントを受け取ると、 それを返さずにread-eventがイベントを直接処理してしまう場合がある。 see Help Functions特殊イベント(special event)と呼ばれる他のイベントも read-eventが直接処理する(see Special Events)。

read-eventを呼んで右矢印のファンクションキーを押すとつぎのようになる。

(read-event)
     => right

read-char Function
この関数はコマンド入力の文字を読み取りそれを返す。 文字を得るまで、文字以外のイベントはすべて破棄する。

最初の例では、ユーザーは文字1ASCIIコード49)を打つ。 2番目の例は、eval-expressionを使って ミニバッファからread-charを呼び出すキーボードマクロの定義である。 read-charはキーボードマクロの直後の文字、つまり、1を読む。 そして、eval-expressionはその戻り値をエコー領域に表示する。

(read-char)
     => 49

;; これを評価するために読者はM-:を使うと仮定する
(symbol-function 'foo)
     => "^[:(read-char)^M1"
(execute-kbd-macro 'foo)
     -| 49
     => nil

read-eventは、あれば現在の入力方式も起動します。 input-method-functionnil以外であれば、 それは関数であるはずです。 read-eventが修飾ビットのない(<SPC>を含む)印字文字を読み取ると、 引数としてイベントを渡してその関数を呼び出します。

input-method-function Variable
これがnil以外であると、その値は現在の入力方式関数を指定する。

注意: この変数をletで束縛しないこと。 この変数はしばしばバッファローカルであり、 入力を読む周囲で束縛すると(読者がこれをもっとも束縛しそうなところ)、 Emacsが入力を待っているときにバッファが非同期に切り替わると、 誤ったバッファに値を復元してしまうことがある。

入力方式関数は、入力として使われるイベントのリストを返すべきです。 (リストがnilであると入力がなかったことを意味し、 read-eventは別のイベントを待つ。) これらのイベントは、 unread-command-events内のイベントよりまえに処理されます。 入力方式関数が返したイベントは、それらが修飾ビットがない印字文字であっても、 入力方式関数に再度渡されることはありません。

入力方式関数がread-eventread-key-sequenceを呼び出すときには、 input-method-functionnilに束縛して 再帰呼び出しを防ぐべきです。

キー列の2番目以降のイベントを読むときには、入力方式関数を呼び出しません。 したがって、それらの文字は、入力方式処理の対象ではありません。 入力方式の処理では、 overriding-local-mapoverriding-terminal-local-mapの値を 検査するのがよいです。 これらの変数のいずれかがnil以外であるときには、 入力方式ではその引数をリストに入れ、 それ以上処理せずにそのリストを返すべきです。


Node:Quoted Character Input, Next:, Previous:Reading One Event, Up:Reading Input

クォートした文字の入力

ユーザーに文字入力を促して、コントロール文字やメタ文字を 文字そのものや文字の8進数コードで手軽に入力できるようにするには、 関数read-quoted-charを使います。 コマンドquoted-insertは、この関数を使っています。

read-quoted-char &optional prompt Function
この関数はread-charに似ているが、 最初に読んだ文字が8進数字文字(0-7)であると、 任意個数の8進数字文字を読み取り(8進数字文字以外が現れると止める)、 その数値の文字コードが表す文字を返す。

最初の文字を読むと中断を抑制するので、 ユーザーはC-gを入力できる。 see Quitting

promptを与えると、それはユーザーへのプロンプトを表す文字列を指定する。 プロンプト文字列はつねにエコー領域に表示され、あとに-が続く。

つぎの例では、ユーザーは8進数177(10進数では127)を打つ。

(read-quoted-char "What character")

---------- Echo Area ----------
What character-177
---------- Echo Area ----------

     => 127


Node:Event Input Misc, Previous:Quoted Character Input, Up:Reading Input

その他のイベント入力機能

本節では、イベントを処理せずに『まえもって覗き見』する方法、 処理待ちの入力の有無の検査方法、処理待ちの入力の破棄方法について述べます。 関数read-passwdも参照してください(see Reading a Password)。

unread-command-events Variable
この変数は、コマンド入力として読まれることを 待っているイベントのリストを保持する。 イベントはリストに現れる順に使われ、使われると1つ1つ取り除かれる。

関数でイベントを読んだあとにそれを使わない場面があるため、 この変数が必要になる。 この変数にイベントを保存すると、 コマンドループやコマンド入力を読む関数によって通常どおり処理される。

たとえば、数値前置引数を実現する関数は、任意個数の数字文字を読み取る。 数字文字でないイベントをみつけたら、そのイベントを読み戻して、 コマンドループが通常どおりに読めるようにする必要がある。 同様に、インクリメンタルサーチでは、この機能を使って 探索においては意味を持たないイベントを読み戻す。 なぜなら、そのようなイベントは探索を終了させ、 通常どおり実行される必要があるからである。

unread-command-eventsに入れられるように キー列からイベントを確実に簡単に取り出す方法は listify-key-sequenceを使うことである(see Strings of Events)。

もっとも最近に読み戻したイベントが最初に再度読まれるように、 普通はこのリストの先頭にイベントを追加する。

listify-key-sequence key Function
この関数は、文字列やベクトルであるkeyを個々のイベントのリストに変換する。 この結果はunread-command-eventsに入れられる。

unread-command-char Variable
この変数は、コマンド入力として読まれる文字を保持する。 値「-1」は、『空』を意味する。

この変数はほとんど廃れており、 かわりにunread-command-eventsを使うべきである。 Emacs 18版以前向けに書かれたプログラムを扱うためだけに存在する。

input-pending-p Function
この関数は、現在、コマンド入力があるかどうかを調べる。 ただちに返るが、入力があれば値tを、 さもなければnilを返す。 入力がないのにtを返すことが稀にある。

last-input-event Variable
last-input-char Variable
この変数は、コマンドの一部として、あるいは、Lispプログラムが明示的に 読み取った最後の端末入力イベントを記録する。

以下の例で、Lispプログラムは文字1ASCIIコード49)を読む。 それがlast-input-eventの値になるが、 (この式を評価するコマンドはC-x C-eと仮定するので) last-command-eventの値はC-eのままである。

(progn (print (read-char))
       (print last-command-event)
       last-input-event)
     -| 49
     -| 5
     => 49

Emacs 18版との互換性のために、別名last-input-charが存在する。

discard-input Function
この関数は端末入力バッファの内容を廃棄し、 定義中のキーボードマクロを取り消す。 これはnilを返す。

以下の例で、フォームを評価しはじめてから、ユーザーは何文字か打つ。 sleep-forが待機を終えると、 discard-inputは待機中に打たれた文字をすべて破棄する。

(progn (sleep-for 2)
       (discard-input))
     => nil


Node:Special Events, Next:, Previous:Reading Input, Up:Command Loop

特殊イベント

特殊イベントは、読まれるとただちに非常に低レベルで処理されます。 関数read-eventはこれらのイベントをそれ自身で処理してしまい、 それらを返すことはありません。

このように処理されるイベントは表示されることはなく、 キー列に組み込まれることもなく、 last-command-event(this-command-keys)の値に 現れることもありません。 特殊イベントが数値引数を破棄することはなく、 unread-command-eventsで読み戻すことはできません。 特殊イベントがキーボードマクロに現れることはなく、 読者がキーボードマクロを定義しているときに、 特殊イベントがキーボードマクロに記録されることはありません。

しかし、それらのイベントは、 読まれた直後にはlast-input-eventに現れますから、 これからイベントの定義で実際のイベントを見ることができます。

iconify-framemake-frame-visibledelete-frameの イベント型は、通常このように処理されます。 特殊イベントをどのように処理するか、 どのイベントが特殊イベントであるかを定義する キーマップは変数special-event-mapにあります(see Active Keymaps)。


Node:Waiting, Next:, Previous:Special Events, Up:Command Loop

時間待ちと入力待ち

待機関数は、指定時間経過するか入力がくるまで待つように設計してあります。 たとえば、ユーザーに表示を眺める時間を与えるために 計算途中で休止したいでしょう。 sit-forは、休止してスクリーンを更新し、 入力がくるとただちに戻ります。 一方、sleep-forはスクリーンを更新せずに休止します。

sit-for seconds &optional millisec nodisp Function
この関数は(処理待ちのユーザーからの入力がなければ)再表示を行い、 seconds秒休止するか、入力がくるまで待つ。 入力がこずに(Event Input Miscinput-pending-pを参照) 指定時間だけ休止した場合は、戻り値はtである。 さもなければ、戻り値はnilである。

引数secondsは整数である必要はない。 それが浮動小数点数であると、sit-forは秒の小数も待つ。 秒単位しか扱えないシステムもあり、 そのようなシステムではsecondsを秒に切り下げる。

省略可能な引数millisecは、ミリ秒単位の追加待ち時間を指定する。 これはsecondsで指定した時間に加えられる。 秒未満を扱えないシステムでは、 millisecに0以外を指定するとエラーになる。

入力がくると再表示をつねに取り止め、 再表示開始まえに入力がくると、いっさい再表示しない。 したがって、処理待ちの入力があると、再表示を強制する方法はない。 しかし、処理待ちの入力がなければ、(sit-for 0)で再表示を強制できる。

nodispnil以外であると、 sit-forは再表示はしないが、 入力がくるとただちに(あるいは指定時間だけ経過すると)戻る。

フレームをアイコンにしたりアイコンにしたフレームを開くと イベントが生成されるため、sit-forは戻る。 see Misc Events

sit-forの普通の目的は、 読者が表示したテキストを読む時間をユーザーに与えることである。

sleep-for seconds &optional millisec Function
この関数は表示を更新せずに単にseconds秒だけ休止する。 入力にはいっさい注意を払わない。 nilを返す。

引数secondsは整数である必要はない。 それが浮動小数点数であると、sleep-forは秒の小数も待つ。 秒単位しか扱えないシステムもあり、 そのようなシステムではsecondsを秒に切り下げる。

省略可能な引数millisecは、ミリ秒単位の追加待ち時間を指定する。 これはsecondsで指定した時間に加えられる。 秒未満を扱えないシステムでは、 millisecに0以外を指定するとエラーになる。

遅延を保証したい場合にsleep-forを使う。

現在時刻を取得する関数についてはSee Time of Day


Node:Quitting, Next:, Previous:Waiting, Up:Command Loop

中断

Lisp関数が動作中にC-gを打つと、 Emacsがなにを行っていても中断を引き起こします。 つまり、もっとも内側の活性なコマンドループに制御が戻ります。

コマンドループがキーボード入力を待っているときにC-gを打っても、 中断を引き起こさずに、普通の入力文字として動作します。 もっとも単純な場合、C-gはコマンドkeyboard-quitを実行しますが、 その効果は中断を引き起こすことですから、読者には区別できないはずです。 しかし、プレフィックスキーに続けてC-gを打つと、 それらは組み合わされて未定義キーになります。 その効果は、前置引数を含めてプレフィックスキーを取り消します。

ミニバッファでは、C-gには別の定義があって、 ミニバッファを強制終了させます。 つまり、ミニバッファから抜け出て中断します。 (単に中断したのでは、ミニバッファ内で コマンドループに戻るだけである。) コマンドループで入力を読んでいるときにC-gで直接中断しない理由は、 このようにミニバッファでその意味を再定義できるようにするためです。 ミニバッファでは、プレフィックスキーに続くC-gは再定義してなく、 プレフィックスキーと前置引数を取り消すという通常の効果を持ちます。 C-gがつねに直接中断するのでは、このようにすることさえ不可能です。

C-gが直接に中断するときには、 変数quit-flagtを設定します。 Emacsはこの変数を適切なときに検査しnilでないと中断します。 したがって、quit-flagnil以外を設定すると 中断を引き起こします。

Cのコードのレベルでは、どこでも中断できるわけではありません。 quit-flagを検査している特別な箇所だけです。 このようにするのは、それ以外の箇所で中断すると Emacsの内部状態に矛盾をきたす可能性があるからです。 中断は安全な場所まで延期されるので、 中断によってEmcasがクラッシュすることはありません。

read-key-sequenceread-quoted-charなどのある種の関数は、 入力を待っている場合であっても中断を完全に抑制します。 中断するかわりに、C-gは入力として働きます。 read-key-sequenceの場合、コマンドループにおいて C-gの特別なふるまいをもたらします。 read-quoted-charの場合、 C-qC-gをクォートできるようになります。

変数inhibit-quitnil以外の値を束縛することで Lisp関数のある部分において中断を抑制できます。 そうすると、C-gはそれでもいつもどおり quit-flagtにしますが、 その通常の結果である中断は抑制されます。 最終的にフォームletの終りで束縛が解除されるなどして inhibit-quitが再度nilになります。 その時点でもquit-flagnil以外であると 要求した中断がただちに起こります。 このふるまいは、プログラムの『臨界領域』では 中断が起こらないことを保証する理想的なものです。

read-quoted-charなどの)ある種の関数では、 C-gは特別に処理され中断を引き起こしません。 inhibit-quittを束縛して入力を読み取り、 inhibit-quitが再度nilになるまえに quit-flagnilにすることでそのようにします。 これをread-quoted-charの定義の以下の抜粋で示しましょう。 最初の入力文字のあとで通常の中断を許す方法も示しています。

(defun read-quoted-char (&optional prompt)
  "...documentation..."
  (let ((message-log-max nil) done (first t) (code 0) char)
    (while (not done)
      (let ((inhibit-quit first)
            ...)
	(and prompt (message "%s-" prompt))
	(setq char (read-event))
	(if inhibit-quit (setq quit-flag nil)))
      ...変数codeに設定する...)
    code))

quit-flag Variable
inhibit-quitnilであれば、 この変数がnil以外であるとEmacsはただちに中断する。 C-gは、inhibit-quitに関わらず、 通常、quit-flagnil以外を設定する。

inhibit-quit Variable
この変数は、quit-flagnil以外の値に設定されたときに Emacsが中断すべきかどうかを決定する。 inhibit-quitnil以外であると、 quit-flagに特別な意味はない。

keyboard-quit コマンド
この関数は(signal 'quit nil)quit条件を通知する。 これは中断と同じことを行う。 (Errorssignalを参照。)

中断として使うC-g以外の特殊文字を使えます。 Terminal Inputの関数set-input-modeを参照してください。


Node:Prefix Command Arguments, Next:, Previous:Quitting, Up:Command Loop

前置コマンド引数

Emacsのほとんどのコマンドは、前置引数(prefix argument)、 つまりコマンド自身のまえに指定された数を利用できます。 (前置引数とプレフィックスキーを混同しないこと。) 前置引数はつねに値で表現され、 nilであると現在は前置引数がないことを表します。 各コマンドは、前置引数を使ってもよいし、無視してもかまいません。

前置引数には2つの表現方法があります。 (raw)と数値(numeric)です。 エディタコマンドループでは、内部的には生の表現を使い、 その情報を保持するLisp変数もそのようにしますが、 コマンドではどちらの表現を要求してもかまいません。

生の前置引数の値にはつぎの可能性があります。

いろいろな前置引数でつぎの関数を呼び出す例を示します。

(defun display-prefix (arg)
  "Display the value of the raw prefix arg."
  (interactive "P")
  (message "%s" arg))

以下は、生の前置引数でdisplay-prefixを呼び出した結果です。

        M-x display-prefix  -| nil

C-u     M-x display-prefix  -| (4)

C-u C-u M-x display-prefix  -| (16)

C-u 3   M-x display-prefix  -| 3

M-3     M-x display-prefix  -| 3      ; (C-u 3と同じ)

C-u -   M-x display-prefix  -| -

M--     M-x display-prefix  -| -      ; (C-u -と同じ)

C-u - 7 M-x display-prefix  -| -7

M-- 7   M-x display-prefix  -| -7     ; (C-u -7と同じ)

Emacsは、前置引数を保持するために2つの変数、 prefix-argcurrent-prefix-argを使います。 他のコマンド向けに前置引数を設定するuniversal-argumentなどの コマンドは、前置引数をprefix-argに保持します。 対照的に、current-prefix-argには 現在のコマンドに対して前置引数を運ぶ役割があり、 この変数に設定しても以後のコマンドに対する前置引数には なんの効果もありません。

通常、コマンドは、interactive宣言により、 「生」か「数値」のいずれの表現の前置引数を使うか指定します。 (See Using Interactive。) あるいは、変数current-prefix-argにある前置引数の値を 関数から直接見てもかまいませんが、 これは見通しのよい方法ではありません。

prefix-numeric-value arg Function
この関数は、有効な生の前置引数の値argからそれに等価な数値を返す。 引数は、シンボル、数、リストのいずれかである。 それがnilであると、戻り値は1である。 -であると、戻り値は-1である。 数であると、その数を返す。 リストであると、リストの(数であるはずの)CARを返す。

current-prefix-arg Variable
この変数は、現在のコマンドに対する生の前置引数を保持する。 コマンドが直接この変数を調べてもよいが、 前置引数を参照する普通の方法は(interactive "P")を使うことである。

prefix-arg Variable
この変数の値は、つぎの編集コマンド向けの生の前置引数である。 後続のコマンド向けの前置引数を指定するuniversal-argumentなどの コマンドは、この変数に設定することで動作する。

last-prefix-arg Variable
まえのコマンドで使われた生の前置引数の値。

つぎのコマンドは、後続のコマンド向けの前置引数を設定するためのものです。 それ以外の目的には呼ばないでください。

universal-argument コマンド
このコマンドは入力を読み取り、後続のコマンド向けの前置引数を指定する。 なにをしているか理解していない限り、読者自身でこのコマンドを呼ばないこと。

digit-argument arg コマンド
このコマンドは、後続のコマンド向けの前置引数に追加する。 引数argは、このコマンドが呼び出されるまえの生の前置引数であり、 前置引数を更新する計算に使われる。 なにをしているか理解していない限り、読者自身でこのコマンドを呼ばないこと。

negative-argument arg コマンド
このコマンドは、後続のコマンド向けの数値前置引数に追加する。 引数argは、このコマンドが呼び出されるまえの生の前置引数であり、 その値の符号を変えて新たな前置引数とする。 なにをしているか理解していない限り、読者自身でこのコマンドを呼ばないこと。


Node:Recursive Editing, Next:, Previous:Prefix Command Arguments, Up:Command Loop

再帰編集

Emacsが動作を始めると、Emacsのコマンドループに自動的に入ります。 このトップレベルのコマンドループからはけっして抜けることはなく、 Emacsが動いている限り動作し続けます。 Lispプログラムからコマンドループを起動することもできます。 そうすると、活性なコマンドループが複数作られることになるので、 それを再帰編集(recursive editing)と呼びます。 再帰編集レベルには、それを起動したコマンドを一時休止させ、 当該コマンドを再開するまでユーザーにどんな編集でも許す効果があります。

再帰編集中に利用可能なコマンドは、トップレベルのコマンドループと 同じものでありキーマップで定義されます。 再帰編集を抜けるための数個の特別なコマンドがあり、 完了すると再帰編集レベルから抜ける別のコマンドもあります。 (再帰編集を抜けるコマンドはつねに利用可能であるが、 再帰編集中でないとなにも行わない。)

再帰編集を含むすべてのコマンドループでは、 コマンドループから実行したコマンドのエラーによって コマンドループから抜け出さないように汎用目的のエラーハンドラを設定します。

ミニバッファでの入力は、特別な種類の再帰編集です。 これには、ミニバッファやミニバッファ用ウィンドウを表示するなどの特別な 処理がありますが、読者が考えるよりは少ないのです。 ミニバッファでは特別なふるまいをするキーもありますが、 それらはミニバッファのローカルマップによるものです。 ウィンドウを切り替えると、Emacsの普通のコマンドを使えます。

再帰編集レベルを起動するには、関数recursive-editを呼び出します。 この関数にはコマンドループが含まれています。 さらに、exitを伴ったcatchの呼び出しもあり、 これにより、exitへ投げることで 再帰編集レベルから抜け出せるようになっています (see Catch and Throw)。 t以外の値を投げると、recursive-editは、 呼び出し側の関数へ普通に戻ります。 コマンドC-M-cexit-recursive-edit)は、これを行います。 値tを投げるとrecursive-editに中断を引き起こし、 1つ上のレベルのコマンドループへ制御を戻します。 これを強制終了(aborting)と呼び、 C-]abort-recursive-edit)で行えます。

ミニバッファを使う場合を除いて、ほとんどのアプリケーションでは 再帰編集を使うべきではありません。 カレントバッファのメジャーモードを 一時的な特別なメジャーモードに変更するほうが、 一般にはユーザーにとってより便利です。 ただし、当該メジャーモードには、 まえのモードに戻るコマンドを用意しておきます。 (rmailのコマンドeは、この方式を使っている。) あるいは、『再帰的に』編集する別のテキストをユーザーに与えたい場合には、 特別なモードの新たなバッファを作成してそれを選択します。 当該モードには、処理を終えてまえのバッファに戻るコマンドを 定義しておきます。 (rmailのコマンドmは、このようにする。)

再帰編集はデバッグに便利です。 ブレークポイントの一種として関数定義に debugの呼び出しを挿入しておくと、 その箇所に達したときにいろいろと調べられます。 debugは再帰編集を起動しますが、デバッガとしての機能も提供します。

query-replaceC-rを打ったり、 C-x qkbd-macro-query)を使ったときにも 再帰編集レベルが使われます。

recursive-edit Function
この関数はエディタコマンドループを起動する。 Emacsの初期化過程で自動的に呼び出され、ユーザーが編集できるようにする。 Lispプログラムから呼ばれると、再帰編集レベルに入る。

以下の例では、関数simple-recは、まず1単語分ポイントを進め、 エコー領域にメッセージを表示して再帰編集に入る。 そうすると、ユーザーは望むことはなんでもできるようになり、 (再帰編集を)抜けるためにC-M-cを打つと、 simple-recの実行を継続する。

(defun simple-rec ()
  (forward-word 1)
  (message "Recursive edit in progress")
  (recursive-edit)
  (forward-word 1))
     => simple-rec
(simple-rec)
     => nil

exit-recursive-edit コマンド
この関数は、(ミニバッファでの入力を含む)もっとも内側の再帰編集から抜ける。 その関数定義は実質的には(throw 'exit nil)である。

abort-recursive-edit コマンド
この関数は、再帰編集から抜けたあとでquitを通知することで、 (ミニバッファでの入力を含む)もっとも内側の再帰編集を 要請したコマンドを強制終了する。 その関数定義は実質的には(throw 'exit t)である。 see Quitting

top-level コマンド
この関数は、すべての再帰編集を抜ける。 すべての計算を抜け出てメインのコマンドループへ直接戻るため、値は返さない。

recursion-depth Function
この関数は再帰編集の現在の深さを返す。 活性な再帰編集がなければ0を返す。


Node:Disabling Commands, Next:, Previous:Recursive Editing, Up:Command Loop

コマンドを禁止する

コマンドを禁止するとは、 コマンドを実行するまえにユーザーの確認を必要とするように コマンドに印を付けることです。 コマンドを禁止するのは、 初心者に混乱をもたらす可能性のあるコマンドに対してや、 コマンドの誤用を防ぐためです。

コマンドを禁止する低レベルの機構は、 コマンドのLispシンボルにnil以外の属性disabledを入れることです。 これらの属性は、通常、ユーザーの.emacsファイルにて つぎのようなLisp式で設定します。

(put 'upcase-region 'disabled t)

数個のコマンドにはデフォルトでこれらの属性がありますから、 .emacsファイルで属性を取り除きます。

属性disabledの値は文字列であり、 コマンドを禁止したことを表すメッセージです。 たとえばつぎのとおりです。

(put 'delete-region 'disabled
     "Text deleted this way cannot be yanked back!\n")

禁止したコマンドを対話的に起動するとどうなるかについて 詳しくはSee Disabling。 コマンドを禁止しても、Lispプログラムから関数として呼び出すことには なんの影響もありません。

enable-command command コマンド
これ以降、特別な確認なしにcommandを実行可能にする。 さらに(ユーザーが了承すれば)ユーザーの.emacsファイルを変更して、 将来のセッションでもそのようにする。

disable-command command コマンド
これ以降、commandの実行には特別な確認を必要とするようにする。 さらに(ユーザーが了承すれば)ユーザーの.emacsファイルを変更して、 将来のセッションでもそのようにする。

disabled-command-hook Variable
禁止したコマンドをユーザーが対話的に起動したとき、 禁止したコマンドのかわりにこのノーマルフックを実行する。 フック関数では、this-command-keysを使って コマンドを実行するためにユーザーがなにを入力したかを調べ、 コマンドそのものを探し出せる。 see Hooks

デフォルトでは、disabled-command-hookには、 ユーザーに処理を進めるかどうかを問い合わせる関数が入っている。


Node:Command History, Next:, Previous:Disabling Commands, Up:Command Loop

コマンド履歴

コマンドループでは、実行した複雑なコマンドの履歴を管理していて、 それらのコマンドを簡単に繰り返せるようにしています。 複雑なコマンドとは、ミニバッファを使って引数を読むコマンドです。 これには、任意のM-xコマンド、任意のM-:コマンド、 ミニバッファから引数を読み取るinteractive指定を持つ任意のコマンドが 含まれます。 コマンド自身の実行中に明示的にミニバッファを使っても、 複雑なコマンドとはみなしません。

command-history Variable
この変数の値は、最近使った複雑なコマンドのリストであり、 各要素は評価すべきフォームを表す。 編集セッション中は、すべての複雑なコマンドを集積するが、 (変数history-lengthで指定される)最大サイズに達すると 新しい要素を追加するたびに古い要素を削除する。
command-history
=> ((switch-to-buffer "chistory.texi")
    (describe-key "^X^[")
    (visit-tags-table "~/emacs/src/")
    (find-tag "repeat-complex-command"))

この履歴リストは、実際にはミニバッファ履歴(see Minibuffer History) の特別な場合です。 要素は文字列ではなく式なのです。

まえのコマンドを編集したり取り出すための専用コマンドがたくさんあります。 コマンドrepeat-complex-commandlist-command-historyは、 ユーザーマニュアル (see Repetition)に説明してあります。 ミニバッファ内では、通常のミニバッファ履歴コマンドを使えます。


Node:Keyboard Macros, Previous:Command History, Up:Command Loop

キーボードマクロ

キーボードマクロは、 コマンドとみなせる入力イベントのまとまった列であり、 キーの定義から構成されます。 Lispにおけるキーボードマクロの表現は、 イベントを含んだ文字列やベクトルです。 キーボードマクロとLispマクロ(see Macros)を混同しないでください。

execute-kbd-macro kbdmacro &optional count Function
この関数はキーボードマクロkbdmacroをイベント列として実行する。 kbdmacroが文字列かベクトルであると、 その中のイベントをユーザーが入力した場合とまったく同様に実行する。 列は単一のキーイベントである必要はない。 通常、キーボードマクロの定義は、複数のキー列を連結したものである。

kbdmacroがシンボルであると、 kbdmacroのかわりにその関数定義を用いる。 それがさらに別のシンボルであると、この処理を繰り返す。 最終的な結果は、文字列かベクトルであること。 結果がシンボルでも文字列でもベクトルでもないと、 エラーを通知する。

引数countは繰り返し回数であり、 kbdmacroをその回数だけ実行する。 countを省略するかnilであると、kbdmacroを1回実行する。 countが0であると、 kbdmacroの実行をエラーに出会うか探索に失敗するまで繰り返す。

execute-kbd-macroを使った例についてはsee Reading One Event

executing-macro Variable
この変数は、現在実行中のキーボードマクロの定義である 文字列やベクトルを保持する。 これがnilであると、現在実行中のマクロはない。 コマンドでこの変数を検査することで、 マクロ実行で起動されたときのふるまいを変更できる。 読者自身はこの変数に設定しないこと。

defining-kbd-macro Variable
この変数は、キーボードマクロを定義中かどうかを表す。 コマンドでこの変数を検査することで、マクロ定義中のふるまいを変更できる。 コマンドstart-kbd-macroend-kbd-macroがこの変数に設定する。 読者自身は設定しないこと。

この変数は現在の端末に対してつねにローカルであり、 バッファに対してローカルにはならない。 see Multiple Displays

last-kbd-macro Variable
この変数は、もっとも最近に定義されたキーボードマクロの定義である。 その値は、文字列かベクトル、あるいは、nilである。

この変数は現在の端末に対してつねにローカルであり、 バッファに対してローカルにはならない。 see Multiple Displays


Node:Keymaps, Next:, Previous:Command Loop, Up:Top

キーマップ

入力イベントとコマンドとのバインディング(対応)は、 キーマップ(keymap)と呼ばれるデータ構造に記録されています。 キーマップの各バインディング(あるいはバインド(bind))は、 個々のイベント型を別のキーマップかコマンドに対応付けます。 イベント型のバインディングがキーマップであると、 後続の入力イベントを探すためにそのキーマップを使います。 コマンドがみつかるまで、これを繰り返します。 この処理全体をキー探索(key lookup)と呼びます。


Node:Keymap Terminology, Next:, Up:Keymaps

キーマップの用語

キーマップ(keymap)は、イベント型を定義に対応させる表です。 (この定義は任意のLispオブジェクトであるが、 コマンドループによる実行においては、特定の型のみが意味を持つ)。 与えられたイベント(あるいはイベント型)とキーマップから、 Emacsはイベントの定義を得ることができます。 イベントは、文字、ファンクションキー、マウス操作です (see Input Events)。

ある単位を構成する入力イベントの列をキー列(key sequence)、 あるいは、略してキー(key)と呼びます。 単一イベントから成る列はつねにキー列であり、複数イベント列もキー列です。

キーマップは、任意のキー列に対するバインディング、 つまり、定義を決定します。 キー列が単一イベントから成るとき、 そのバインディングはキーマップ内の当該イベントの定義です。 複数のイベントから成るキー列のバインディングは、 繰り返し処理で探します。 つまり、最初のイベントのバインディングを探すと、 それはキーマップであるはずです。 続いて、そのキーマップから2番目のイベントのバインディングを探します。 これをキー列のすべてのイベントを使い尽くすまで行います

キー列のバインディングがキーマップであると、 そのキー列をプレフィックスキー(prefix key)と呼びます。 さもなければ、(追加できるイベントがないので) 完全なキー(complete key)と呼びます。 バインディングがnilであると、キーは未定義であるといいます。 プレフィックスキーの例は、C-cC-xC-x 4です。 定義されている完全なキーの例は、X、<RET>、C-x 4 C-fです。 未定義な完全なキーの例は、C-x C-gC-c 3です。 詳しくは、See Prefix Keys

キー列のバインディングを探す際の規則では、 (最後のイベントのまえまでにみつかる)途中のバインディングは すべてキーマップであると仮定します。 これが満たされないと、イベントの列があるまとまりを構成せず、 1つのキー列になりません。 いいかえれば、有効なキー列の末尾からいくつかのイベントを取りさると、 つねにプレフィックスキーになる必要があります。 たとえば、C-f C-nはキー列ではありません。 C-fはプレフィックスキーではないので、 C-fで始まる列はキー列ではありません。

複数イベントから成るキー列の候補は、 プレフィックスキーのバインディングに依存します。 したがって、キーマップが異なればそれらは異なり、 バインディングを変更するとそれらは変わります。 しかし、単一イベントから成る列は、プレフィックスに依存しないので、 つねにキー列です。

ある時点には、複数個の主キーマップが活性です。 つまり、キーバインディングの探索に使われます。 それらは、 すべてのバッファが共有するグローバルマップ(global map)、 特定のメジャーモードに関連付けられたローカルマップ(local keymap)、 現在オンにしてあるマイナモードに属する マイナモードキーマップ(minor mode keymaps)です。 (すべてのマイナモードにキーマップがあるわけではない。) ローカルキーマップのバインディングは、 対応するグローバルなバインディングを隠します(つまり優先する)。 マイナモードキーマップは、ローカルとグローバルの両方のキーマップを隠します。 詳しくはSee Active Keymaps


Node:Format of Keymaps, Next:, Previous:Keymap Terminology, Up:Keymaps

キーマップの形式

キーマップは、そのCARがシンボルkeymapであるリストです。 リストの残りの要素がキーマップのキーバインディングを定義します。 オブジェクトがキーマップであるかどうか検査するには、 関数keymapp(下記参照)を使います。

キーマップでは、シンボルkeymapのうしろに、 さまざまな種類の要素が現れます。

(type . binding)
イベント型typeに対する1つのバインディングを指定する。 普通の各バインディングは、文字やシンボルである特定のイベント型に 適用される。 see Classifying Events
(t . binding)
デフォルトのキーバインディングを指定する。 キーマップの他の要素に一致しない任意のイベントには、 そのバインディングとして指定したbindingを与える。 デフォルトのバインディングにより、 すべてを列挙せずに可能なすべてのイベントにバインドできる。 デフォルトのバインディングを有するキーマップは、 任意の低優先順位のキーマップを隠してしまう。
vector
キーマップの要素がベクトルであると、 当該ベクトルをASCII文字全体、つまり、コード0から127に対する バインディングとみなす。 ベクトルのn番目の要素は、コードnの文字に対する バインディングである。 これは、多くのバインディングを記録するコンパクトな方法である。 このようなベクトルのキーマップを完全なキーマップ(full keymap)と呼ぶ。 それ以外のキーマップを疎なキーマップ(sparse keymaps)と呼ぶ。

キーマップにベクトルがあると、ベクトルの要素がnilであっても ベクトルが各ASCII文字のバインディングをつねに定義する。 そのようなnilのバインディングは、 ASCII文字に対しては キーマップのデフォルトのキーバインディングを無効にする。 しかし、ASCII文字以外のイベントに対しては、 デフォルトのバインディングが意味を持つ。 nilのバインディングが 低優先順位のキーマップを隠すことはない。 つまり、ローカルマップがnilのバインディングを与えると、 Emacsはグローバルマップのバインディングを使う。

string
バインディングに加えて、 キーマップでは、要素として文字列を持つこともできる。 これを全面プロンプト文字列(overall prompt string)と呼び、 キーマップをメニューとして使うことを可能にする。 see Menu Keymaps

キーマップは、メタ文字に対するバインディングを直接には記録していません。 そのかわりに、キー探索においては、メタ文字は2文字から成る列とみなし、 先頭文字は<ESC>(あるいは、meta-prefix-charの現在値)です。 つまり、キーM-aは実際には<ESC> aと表現され、 そのグローバルなバインディングは esc-mapaでみつかります(see Prefix Keys)。

Lispモードに対するローカルキーマップの例を示します。 これは疎なキーマップです。 <DEL>、<TAB>、C-c C-lM-C-qM-C-xに対する バインディングを定義しています。

lisp-mode-map
=>
(keymap
 ;; <TAB>
 (9 . lisp-indent-line)
 ;; <DEL>
 (127 . backward-delete-char-untabify)
 (3 keymap
    ;; C-c C-l
    (12 . run-lisp))
 (27 keymap
     ;; M-C-q<ESC> C-qとみなされる
     (17 . indent-sexp)
     ;; M-C-x<ESC> C-xとみなされる
     (24 . lisp-send-defun)))

keymapp object Function
この関数は、objectがキーマップであればtを返し、 さもなければnilを返す。 より正確には、この関数は、 そのCARkeymapであるリストかどうかを検査する。
(keymapp '(keymap))
    => t
(keymapp (current-global-map))
    => t


Node:Creating Keymaps, Next:, Previous:Format of Keymaps, Up:Keymaps

キーマップの作成

ここでは、キーマップを作成するための関数について述べます。

make-keymap &optional prompt Function
この関数は新たに完全なキーマップ (つまり、すべてのASCII文字に対する定義を収めた 長さ128のベクトル)を作成しそれを返す。 新たなキーマップでは、すべてのASCII文字に対するバインディングは nilであり、それ以外の種類のイベントに対するバインディングはない。
(make-keymap)
    => (keymap [nil nil nil ... nil nil])

promptを指定すると、 それはキーマップに対する全面プロンプト文字列になる。 全面プロンプト文字列はメニューキーマップ (see Menu Keymaps)に有用である。

make-sparse-keymap &optional prompt Function
この関数は、新たに空の疎なキーマップを作成しそれを返す。 新たなキーマップにはイベントに対するバインディングはいっさいない。 引数promptは、make-keymapの場合同様、 プロンプト文字列を指定する。
(make-sparse-keymap)
    => (keymap)

copy-keymap keymap Function
この関数はkeymapのコピーを返す。 keymapにバインディングとして直接現れる任意のキーマップも 任意のレベルまで再帰的にコピーされる。 しかし、文字に対する定義が、その関数定義がキーマップであるような シンボルに出会うと再帰的なコピーを行わないため、 同じシンボルが新たなコピーにも現れる。
(setq map (copy-keymap (current-local-map)))
=> (keymap
     ;; (これはメタ文字を意味する)
     (27 keymap
         (83 . center-paragraph)
         (115 . center-line))
     (9 . tab-to-tab-stop))

(eq map (current-local-map))
    => nil
(equal map (current-local-map))
    => t


Node:Inheritance and Keymaps, Next:, Previous:Creating Keymaps, Up:Keymaps

継承とキーマップ

キーマップでは、親キーマップ(parent keymap)と呼ぶ別のキーマップの バインディングを継承できます。 そのようなキーマップはつぎのようになります。

(keymap bindings... . parent-keymap)

このキーマップは、キーを探索する時点において parent-keymapが有するすべてのバインディングを継承しますが、 それらにはbindingsが追加されたり優先します。

define-keyや他のキーバインディング関数でparent-keymapの バインディングを変更すると、それらの変更は、 bindingsで隠されない限り継承側のキーマップからも見えます。 その逆は真ではありません。 define-keyで継承側のキーマップを修正すると、 それはbindingsに影響するだけでparent-keymapには影響しません。

親キーマップを用いたキーマップを作成する正しい方法は、 set-keymap-parentを使うことです。 親キーマップを用いたキーマップを直接作成するようなコードがある場合には、 set-keymap-parentを用いるようにプログラムを変更してください。

keymap-parent keymap Function
この関数は、キーマップkeymapの親キーマップを返す。 keymapに親がなければkeymap-parentnilを返す。

set-keymap-parent keymap parent Function
キーマップkeymapの親キーマップとしてparentを設定し、 parentを返す。 parentnilであると、 この関数はkeymapに親キーマップをいっさい与えない。

keymapに(プレフィックスキー用のバインディングである) サブマップがあれば、それらもparentが指定するプレフィックスキーを 反映する新たな親マップを受け取る。

text-mode-mapからキーマップを継承する方法を示します。

(let ((map (make-sparse-keymap)))
  (set-keymap-parent map text-mode-map)
  map)


Node:Prefix Keys, Next:, Previous:Inheritance and Keymaps, Up:Keymaps

プレフィックスキー

プレフィックス(prefix key)とは、 そのバインディングがキーマップであるキー列のことです。 そのキーマップが、プレフィックスキー以降のキーでなにをするかを定義します。 たとえば、C-xはプレフィックスキーであり、 変数ctl-x-mapに保持されたキーマップを使います。 このキーマップは、C-xで始まるキー列に対するバインディングを定義します。

Emacsの標準プレフィックスキーのなかには、 Lisp変数にも保持されたキーマップを使うものがあります。

プレフィックスキーのキーマップバインディングは、 当該プレフィックスキーに続くイベントを探すために使われます。 (その関数定義がキーマップであるシンボルでもよい。 効果は同じであるが、シンボルはプレフィックスキーに対する名前として働く。) したがって、C-xのバインディングは シンボルControl-X-prefixであり、 その関数セルがコマンドC-x用のキーマップを保持している。 (ctl-x-mapの値も同じキーマップである。)

プレフィックスキーの定義は、任意の活性なキーマップにあってかまいません。 プレフィックスキーとしてのC-cC-xC-h、<ESC>の 定義はグローバルマップにあるので、これらのプレフィックスキーは つねに利用できます。 メジャーモードやマイナモードでは、 プレフィックスキーの定義をローカルキーマップや マイナモードキーマップに入れることで、 キーをプレフィックスとして再定義できます。 See Active Keymaps

複数の活性なキーマップにおいて、キーがプレフィックスと定義されていると、 さまざまな定義は実質的には併合されます。 マイナモードキーマップで定義されたコマンドが最優先で、 つぎにローカルマップのプレフィックス定義、 そしてグローバルマップのプレフィックス定義が続きます。

以下の例では、ローカルキーマップにおいて、 C-pC-xに等価なプレフィックスキーにします。 続いてC-p C-fのバインディングを C-x C-fのように関数find-fileにします。 キー列C-p 6はどの活性なキーマップでもみつかりません。

(use-local-map (make-sparse-keymap))
    => nil
(local-set-key "\C-p" ctl-x-map)
    => nil
(key-binding "\C-p\C-f")
    => find-file

(key-binding "\C-p6")
    => nil

define-prefix-command symbol Function
この関数は、symbolをプレフィックスキーの バインディングとして使えるように準備する。 つまり、完全なキーマップを作成し、 symbolの関数定義にそのキーマップを保存する。 以後、symbolにキー列をバインドすると、 当該キー列をプレフィックスキーに入る。

この関数は、変数としてのsymbolにも値としてキーマップを設定する。 symbolを返す。


Node:Active Keymaps, Next:, Previous:Prefix Keys, Up:Keymaps

活性なキーマップ

Emacsには、通常、たくさんのキーマップがあります。 ある時点では、それらの数個が活性になっていて、 ユーザー入力の解釈に関与します。 それらは、グローバルキーマップ、カレントバッファのローカルキーマップ、 オンになっているマイナモードのキーマップです。

グローバルキーマップ(global keymap)は、 C-fのようなカレントバッファに依存せずに 定義されたキーのバインディングを保持します。 変数global-mapはこのキーマップを保持していて、 このキーマップはつねに活性です。

各バッファには別のキーマップ、つまり、 バッファのローカルキーマップ(local keymap)があり、 キーに対する新しい定義や無効にする定義を保持しています。 カレントバッファのローカルキーマップは、 overriding-local-mapで無効にしない限り、つねに活性です。 テキスト属性により、バッファの特定部分に対する 代替ローカルマップを指定できます。 Special Propertiesを参照してください。

各マイナモードもキーマップを持てます。 その場合、マイナモードがオンであると当該キーマップは活性です。

変数overriding-local-mapnil以外であると、 バッファのローカルキーマップとそのすべてのマイナモードキーマップに 取ってかわるローカルキーマップを指定します。

キーが入力されるとどのコマンドを実行するかを決定するために、 すべての活性なキーマップを一緒に使います。 Emacsは、キーマップの1つでバインディングがみつかるまで、 優先順位が高いほうからこれらのキーマップを1つ1つ探索します。 1つのキーマップで探索する処理のことを キー探索(key lookup)といいます。 Key Lookupを参照してください。

通常、Emacsはまずminor-mode-map-alistで指定される順に マイナモードキーマップでキーを探します。 キーに対するバインディングがなければ、 Emacsはローカルキーマップで探します。 そこにもバインディングがなければ、 Emacsはグローバルキーマップで探します。 しかし、overriding-local-mapnil以外であれば、 Emacsはまずそのキーマップで探してから、 グローバルキーマップで探します。

同じメジャーモードを使う各バッファは、通常、同じローカルキーマップを 使うので、キーマップはモードにローカルであると考えることができます。 (たとえばlocal-set-keyを使って)バッファのローカルキーマップを 修正すると、当該キーマップを共有している別のバッファでも その修正が見えます。

Lispモードや他の数個のメジャーモードで使われるローカルキーマップは、 それらのモードがまだ使われていなくても存在します。 そのようなローカルキーマップは、lisp-mode-mapなどの変数の値です。 使用頻度の低いほとんどのメジャーモードでは、 セッションで始めてそのモードを使ったときに ローカルキーマップを作成します。

ミニバッファにもローカルキーマップがあります。 それにはさまざまな補完コマンドや脱出コマンドが含まれます。 See Intro to Minibuffers

Emacsには、別の用途のキーマップもあります。 read-key-sequenceでイベントを変換するためのものです。 See Translating Input

標準的なキーマップの一覧についてはSee Standard Keymaps

global-map Variable
この変数は、Emacsがキーボード入力をコマンドに対応させるための デフォルトのグローバルキーマップを保持する。 グローバルキーマップは、通常、このキーマップである。 デフォルトのグローバルキーマップは、 すべての印字文字にself-insert-commandをバインドする 完全なキーマップである。

グローバルマップのバインディングを修正することは実用的ですが、 この変数には、動作開始時のキーマップ以外の値は設定しないこと。

current-global-map Function
この関数は、現在のグローバルキーマップを返す。 global-mapを変更していなければ、 これはglobal-mapの値と同じである。
(current-global-map)
=> (keymap [set-mark-command beginning-of-line ...
            delete-backward-char])

current-local-map Function
この関数は、カレントバッファのローカルキーマップを返す。 なければnilを返す。 つぎの例では、(lisp対話モードを使っている)バッファ*scratch*の キーマップは疎なキーマップであり、 ASCIIコード27の<ESC>に対する指定も別の疎なキーマップである。
(current-local-map)
=> (keymap
    (10 . eval-print-last-sexp)
    (9 . lisp-indent-line)
    (127 . backward-delete-char-untabify)
    (27 keymap
        (24 . eval-defun)
        (17 . indent-sexp)))

current-minor-mode-maps Function
この関数は、現在オンになっているマイナモードのキーマップのリストを返す。

use-global-map keymap Function
この関数は、キーマップkeymapを新たな現在のグローバルキーマップとする。 これはnilを返す。

グローバルキーマップを変更することは、とうてい普通のことではない。

use-local-map keymap Function
この関数は、キーマップkeymapをカレントバッファの 新たなローカルキーマップとする。 keymapnilであると、 バッファにはローカルキーマップがなくなる。 use-local-mapnilを返す。 ほとんどのメジャーモードコマンドは、この関数を使う。

minor-mode-map-alist Variable
この変数は、変数の値に応じて活性になっている/いないキーマップを 記述する連想リストである。 その要素はつぎの形である。
(variable . keymap)

変数variableの値がnil以外であれば、 キーマップkeymapは活性である。 典型的には、variableはマイナモードをオン/オフする変数である。 see Keymaps and Minor Modes

minor-mode-map-alistの要素とminor-mode-alistの要素とは、 異なる構造であることに注意してほしい。 キーマップは要素のCDRである必要があり、 要素のCADRがキーマップであるようなリストではだめである。 CADRは、(リストの)キーマップであるか、 関数定義がキーマップであるシンボルである。

複数のマイナモードキーマップが活性な場合、 それらの優先順位は、minor-mode-map-alistでの順番である。 読者は、互いに干渉しないようにマイナモードを設計する必要がある。 正しくできていれば、順序は関係ないはずである。

マイナモードについて詳しくはKeymaps and Minor Modesを参照。 minor-mode-key-binding(see Functions for Key Lookup)も参照のこと。

minor-mode-overriding-map-alist Variable
この変数は、メジャーモードから特定のマイナモード向けのキーバインディングを 無効にするためのものである。 この連想リストの要素は、minor-mode-map-alistの要素と同じ形で、 (variable . keymap)である。

minor-mode-overriding-map-alistの要素として変数が現れると、 当該要素が指定するキーマップで、 minor-mode-map-alist内の同じ変数で指定したキーマップを 完全に置き換える。

minor-mode-overriding-map-alistは、すべてのバッファにおいて、 自動的にバッファにローカルになる。

overriding-local-map Variable
nil以外の値であると、この変数は、 バッファのローカルキーマップ、ならびに、すべてのマイナモードキーマップの かわりに用いるキーマップを保持する。 このキーマップは、現在のグローバルキーマップを除く、 他のすべての活性なキーマップを無効にする。

overriding-terminal-local-map Variable
nil以外であると、この変数は、 overriding-local-map、および、バッファのローカルキーマップと すべてのマイナモードキーマップのかわりに用いるキーマップを保持する。

この変数はつねに現在の端末に対してローカルであり、 バッファに対してローカルにはならない。 see Multiple Displays。 これはインクリメンタルサーチモードの実装に使われている。

overriding-local-map-menu-flag Variable
この変数がnil以外であれば、 overriding-local-mapoverriding-terminal-local-mapの値は、 メニューバーの表示に影響する。 デフォルト値はnilであり、 そのため、それらのマップはメニューバーには影響しない。

これら2つのキーマップ変数は、メニューバーの表示に影響しないときであっても、 メニューバーを用いて入力したキー列の実行には影響することに注意してほしい。 そのため、メニューバーのキー列が到着したら、 そのキー列を探索し実行するまえに、これらの変数をクリアすべきである。 これらの変数を使うモードでは、典型的にはつぎのようにする。 つまり、モードで処理できないイベントは『読み戻し』てモードから抜ける。

special-event-map Variable
この変数は特殊イベント用のキーマップを保持する。 イベント型のバインディングがこのキーマップにあれば、 そのイベントは特殊イベントであり、 read-eventが当該イベントのバインディングを直接実行する。 see Special Events


Node:Key Lookup, Next:, Previous:Active Keymaps, Up:Keymaps

キー探索

キー探索(key lookup)とは、 与えられたキーマップからキー列のバインディングを捜し出す処理です。 バインディングを実際に実行することは、キー探索ではありません。

キー探索では、キー列の各イベントのイベント型のみを使い、 イベントの他の部分は無視します。 実際、キー探索に使われるキー列では、 マウスイベント全体(リスト)ではなく そのイベント型(シンボル)のみを指定します。 See Input Events。 そのような『キー列』は、command-executeの動作には不十分ですが、 キーの探索や再バインディングには十分です。

キー列が複数のイベントから構成される場合、 キー探索ではイベントを順番に処理します。 先頭のイベントのバインディングを探しますが、 それはキーマップであるはずです。 続いて、そのキーマップから2番目のイベントのバインディングを探します。 これをキー列のすべてのイベントを使い尽くすまで行います。 (このように探した最後のイベントに対するバインディングは、 キーマップであたっりそうでないかもしれない。) つまり、キー探索処理は、 キーマップから単一イベントを探索するという単純な処理として定義できます。 これがどのように行われるかは、 キーマップ内のイベントに対応付けられたオブジェクトの型に依存します。

キーマップでイベント型を探してみつかった値のことを キーマップ項目(keymap entry)という単語で表します。 (これには、メニューキーバインディングにある 項目文字列や他の追加要素を含まない。 というのは、lookup-keyや他のキー探索関数は、 それらを戻り値として返さないからである。) キーマップ項目として任意のLispオブジェクトをキーマップに保存できますが、 キー探索においてそのすべてが意味を持つとは限りません。 意味のある種類のキー項目をつぎに示します。

nil
nilは、探索に使ったここまでのイベントが 未定義キーを構成することを意味する。 キーマップにイベント型が記載されてなく、かつ、 デフォルトのバインディングもない場合には、 そのイベント型に対しては、バインディングがnilであるのと等価。
command
探索に使ったここまでのイベントは完全なキーを構成し、 そのバインディングはコマンドcommandである。 see What Is a Function
array
配列(文字列やベクトル)は、キーボードマクロである。 探索に使ったここまでのイベントは完全なキーを構成し、 そのバインディングは配列arrayである。 詳しくはKeyboard Macrosを参照。
keymap
探索に使ったここまでのイベントはプレフィックスキーを構成する。 キー列のつぎのイベントはこのキーマップkeymapで探す。
list
リストの意味は、リストの要素の型に依存する。
symbol
シンボルsymbolのかわりにその関数定義を使う。 それがまたシンボルであると、この処理を何回でも繰り返す。 最終的にこれは、キーマップ、コマンド、キーボードマクロの いずれかのオブジェクトになるはずである。 キーマップやコマンドであるリストは許されるが、 シンボルを介しては間接項目は使えない。

キーマップやキーボードマクロ(文字列やベクトル)は正しい関数ではないので、 関数定義としてキーマップ、文字列、ベクトルを持つシンボルは、 正しい関数ではない。 しかし、キーバインディングとしては正しい。 定義がキーボードマクロである場合には、そのシンボルは command-executeの引数としても正しい (see Interactive Call)。

シンボルundefinedについて特記しておく。 これは、キーを未定義として扱うことを意味する。 正確には、キーは定義されており、 そのバインディングはコマンドundefinedである。 しかし、そのコマンドは、未定義キーに対して自動的に行われることと 同じことを行う。 つまり、(dingを呼び出して)ベルを鳴らすが、 エラーは通知しない。

undefinedは、グローバルキーバインディングを無効にして キーをローカルに『未定義』にするためにローカルキーマップで使われる。 nilのローカルバインディングでは、 グローバルバインディングを無効にしないため、こうはならない。

その他
その他の型のオブジェクトであると、 探索に使ったここまでのイベントは完全なキーを構成し、 当該オブジェクトがそのバインディングであるが、 当該バインディングはコマンドとしては実行できない。

まとめると、キー項目は、キーマップ、コマンド、キーボードマクロ、 これら3つのいずれかになるシンボル、間接項目、nilです。 2つの文字をコマンドに、1つを別のキーマップに対応付ける 疎なキーマップの例を示します。 このキーマップは、emacs-lisp-mode-mapの通常の値です。 ここで、それぞれ、9は<TAB>、 127は<DEL>、27は<ESC>、17はC-q、 24はC-xの文字コードであることに注意してください。

(keymap (9 . lisp-indent-line)
        (127 . backward-delete-char-untabify)
        (27 keymap (17 . indent-sexp) (24 . eval-defun)))


Node:Functions for Key Lookup, Next:, Previous:Key Lookup, Up:Keymaps

キー探索関数

ここでは、キー探索に関わる関数や変数について述べます。

lookup-key keymap key &optional accept-defaults Function
この関数はキーマップkeymapにおけるkeyの定義を返す。 本章で述べる他の関数は、lookup-keyを用いてキーを探す。 例を示す。
(lookup-key (current-global-map) "\C-x\C-f")
    => find-file
(lookup-key (current-global-map) "\C-x\C-f12345")
    => 2

文字列やベクトルであるkeyが、 keymapで指定されたプレフィックスキーに対して正しいキー列でなければ、 keyは『長すぎる』のであって、 1つのキー列に収まらない余分なイベントが末尾にある。 その場合、戻り値は数であり、 完全なキーを構成するkeyの先頭からのイベント数を表す。

accept-defaultsnil以外であると、 lookup-keyは、keyの特定のイベントに 対するバインディングだけでなく、 デフォルトのバインディングも考慮する。 さもなければ、lookup-keyは、 keyの特定のイベントに対するバインディングだけを報告し、 特に指定しない限りデフォルトのバインディングは無視する。 (それには、keyの要素としてtを与える。 Format of Keymapsを参照。)

keyにメタ文字が含まれる場合、 当該文字は暗黙のうちに2文字の列、 つまり、meta-prefix-charの値と対応する非メタ文字 に置き換えられる。 したがって、つぎの最初の例は、2番目の例に変換して処理される。

(lookup-key (current-global-map) "\M-f")
    => forward-word
(lookup-key (current-global-map) "\ef")
    => forward-word

read-key-sequenceと異なり、 この関数は、情報を欠落するようには指定されたイベントを修正しない (see Key Sequence Input)。 特に、文字を小文字に変換したり、 ドラッグイベントをクリックイベントに変換したりはしない。

undefined コマンド
キーを未定義にするためにキーマップで使われる。 dingを呼び出すが、エラーにはならない。

key-binding key &optional accept-defaults Function
この関数は、すべての活性なキーマップを試して keyに対するバインディングを返す。 キーマップでkeyが未定義であると結果はnil

引数accept-defaultsは、lookup-key(上記)と同様に、 デフォルトのバインディングを調べるかどうか制御する。

keyが文字列でもベクトルでもないとエラーを通知する。

(key-binding "\C-x\C-f")
    => find-file

local-key-binding key &optional accept-defaults Function
この関数は、現在のローカルキーマップから keyに対するバインディングを返す。 未定義ならばnilを返す。

引数accept-defaultsは、lookup-key(上記)と同様に、 デフォルトのバインディングを調べるかどうか制御する。

global-key-binding key &optional accept-defaults Function
この関数は、現在のグローバルキーマップから keyに対するバインディングを返す。 未定義ならばnilを返す。

引数accept-defaultsは、lookup-key(上記)と同様に、 デフォルトのバインディングを調べるかどうか制御する。

minor-mode-key-binding key &optional accept-defaults Function
この関数は、すべてのオンになっているマイナモードにおける keyのバインディングのリストを返す。 より正確には、対(modename . binding)を要素とする 連想リストを返す。 ここで、modenameはマイナモードをオンにする変数であり、 bindingは当該モードにおけるkeyのバインディングである。 keyにマイナモードでのバインディングがなければ、 値はnilである。

最初にみつかったバインディングがプレフィックスの定義 (キーマップかキーマップとしてのシンボル)でなければ、 残りのマイナモードからのバインディングは完全に隠されてしまうので それらは省略する。 同様に、プレフィックスバインディングに 続く非プレフィックスバインディングも省略する。

引数accept-defaultsは、lookup-key(上記)と同様に、 デフォルトのバインディングを調べるかどうか制御する。

meta-prefix-char Variable
この変数は、メタプレフィックス文字の文字コードである。 メタ文字をキーマップで探索するために2文字列に変換するときに使われる。 結果が有用であるためには、 この値はプレフィックスイベント(see Prefix Keys)であるべきである。 デフォルト値は27、<ESC>のASCIIコードである。

meta-prefix-charの値が27である限り、 キー探索ではM-b<ESC> bに変換し、 通常、これはコマンドbackward-wordと定義されている。 しかし、meta-prefix-charC-xのコードである24を設定すると、 EmacsはM-bC-x bに変換し、 その標準のバインディングはコマンドswitch-to-bufferである。 これを以下に示す。

meta-prefix-char                    ; デフォルト値
     => 27
(key-binding "\M-b")
     => backward-word
?\C-x                               ; 文字の表示表現
     => 24
(setq meta-prefix-char 24)
     => 24
(key-binding "\M-b")
    => switch-to-buffer            ; ここでM-bと打つと
                                    ; C-x bと打つのと同じ

(setq meta-prefix-char 27)          ; 混乱を避けるために
     => 27                         ; デフォルト値に戻す!


Node:Changing Key Bindings, Next:, Previous:Functions for Key Lookup, Up:Keymaps

キーバインディングの変更

キーを再バインドするには、キーマップにおける当該項目を変更します。 グローバルキーマップでバインディングを変更すると、 その変更はすべてのバッファで効果を発揮します (ただし、ローカルキーマップでグローバルバインディングを 隠しているバッファでは直接の効果はない)。 カレントバッファのローカルキーマップで変更すると、 通常、同じメジャーモードを使っているすべてのバッファに影響します。 関数global-set-keylocal-set-keyは、 これらの操作を行うための便利なインターフェイスです (see Key Binding Commands)。 より汎用の関数define-keyを使うこともできますが、 変更対象のキーマップを明示する必要があります。

キー列の再バインドを書くときには、 コントロール文字やメタ文字向けの 特別なエスケープシーケンスを使うのがよいです(see String Type)。 構文\C-は後続の文字がコントロール文字であること、 構文\M-は後続の文字がメタ文字であることを意味します。 したがって、文字列"\M-x"は単一のM-xを含むと読まれ、 "\C-f"は単一のC-fを含むと読まれ、 "\M-\C-x""\C-\M-x"はいずれも単一のC-M-xを 含むと読まれます。 同じエスケープシーケンスは、 ベクトルでも使え、文字列が許されない他の場面でも使えます。 たとえば、[?\C-\H-x home]です。 See Character Type

キーを定義したり探索する関数では、 ベクトルで表したキー列内のイベント型に対して別の構文、 つまり、修飾子名と1つの基本イベント(文字やファンクションキー名) から成るリストを受け付けます。 たとえば、(control ?a)?\C-aに等価であり、 (hyper control left)C-H-leftに等価です。 このようなリストの利点の1つは、 コンパイル済みのファイルに修飾ビットの数値が現れないことです。

以下の関数では、keymapがキーマップでなかったり、 keyがキー列を表す文字列やベクトルでないと、エラーを通知します。 リストであるイベントの省略形としてイベント型(シンボル)を使えます。

define-key keymap key binding Function
この関数は、キーマップkeymapにおいて キーkeyに対するバインディングを設定する。 (keyが複数イベントの場合、 keymapから辿った別のキーマップが実際には変更される。) 引数bindingは任意のLispオブジェクトであるが、 ある種の型のものだけが意味を持つ。 (意味のある型の一覧については、Key Lookupを参照。) define-keyが返す値はbindingである。

keyのおのおののプレフィックスはプレフィックスキーである (キーマップにある)か未定義であること。 さもなければ、エラーを通知する。 keyのプレフィックスに未定義なものがあると、 define-keyは当該プレフィックスをプレフィックスキーと定義し、 keyの残りの部分を指定どおりに定義できるようにする。

keymapkeyのバインディングがなければ、 新たなバインディングをkeymapの先頭に追加する。 キーマップ内のバインディングの順序は多くの場合関係ないが、 メニューキーマップでは意味を持つ(see Menu Keymaps)。

疎なキーマップを作成し、そこにバインディングを作る例を示します。

(setq map (make-sparse-keymap))
    => (keymap)
(define-key map "\C-f" 'forward-char)
    => forward-char
map
    => (keymap (6 . forward-char))

;; C-x用の疎なサブマップを作り、
;; そこにfのバインディングを入れる
(define-key map "\C-xf" 'forward-word)
    => forward-word
map
=> (keymap
    (24 keymap                ; C-x
        (102 . forward-word)) ;      f
    (6 . forward-char))       ; C-f

;; C-pctl-x-mapにバインドする
(define-key map "\C-p" ctl-x-map)
;; ctl-x-map
=> [nil ... find-file ... backward-kill-sentence]

;; ctl-x-mapで、C-ffooにバインドする
(define-key map "\C-p\C-f" 'foo)
=> 'foo
map
=> (keymap     ; fooctl-x-mapの中にある
    (16 keymap [nil ... foo ... backward-kill-sentence])
    (24 keymap
        (102 . forward-word))
    (6 . forward-char))

C-p C-fに対する新しいバインディングは、 実際にはctl-x-mapの項目を変更していて、 これには、C-p C-fとデフォルトのグローバルキーマップ内の C-x C-fの両方のバインディングを変更する効果がある ことに注意してください。

substitute-key-definition olddef newdef keymap &optional oldmap Function
この関数は、keymap内のolddefにバインドされたキーの olddefnewdefに置き換える。 いいかえると、olddefに出会うたびにそれをnewdefに置き換える。 関数はnilを返す。

たとえば、Emacsの標準のバインディングであると、 つぎの例はC-x C-fを再定義する。

(substitute-key-definition
 'find-file 'find-file-read-only (current-global-map))

oldmapnil以外であると、 そのバインディングによってどのキーを再バインドするかを決定する。 再バインディングはkeymapで行い、oldmapではない。 つまり、別のキーマップ内のバインディングの制御のもとに、 キーマップを変更できる。 たとえば、

(substitute-key-definition
  'delete-backward-char 'my-funny-delete
  my-map global-map)

では、グローバルには標準の削除コマンドにバインドされているキーに対しては、 my-mapでは特別な削除コマンドにする。

変更前後のキーマップを以下に示す。

(setq map '(keymap
            (?1 . olddef-1)
            (?2 . olddef-2)
            (?3 . olddef-1)))
=> (keymap (49 . olddef-1) (50 . olddef-2) (51 . olddef-1))

(substitute-key-definition 'olddef-1 'newdef map)
=> nil
map
=> (keymap (49 . newdef) (50 . olddef-2) (51 . newdef))

suppress-keymap keymap &optional nodigits Function
この関数は、完全なキーマップkeymapの内容を変更し、 すべての印字文字を未定義にする。 より正確には、それらにコマンドundefinedをバインドする。 これにより、通常のテキストの挿入を不可能にする。 suppress-keymapnilを返す。

nodigitsnilであると、 suppress-keymapは、 数字文字ではdigit-argumentを実行し、 -ではnegative-argumentを実行するように定義する。 さもなければ、それらも他の印字文字と同様に未定義にする。

関数suppress-keymapは、 yankquoted-insertなどのコマンドを抑制しないので、 バッファを変更不可能にするわけではない。 バッファの変更を禁止するには、バッファを読み出し専用にする (see Read Only Buffers)。

この関数はkeymapを変更するため、 読者は、通常、新たに作成したキーマップに対して使うであろう。 ある目的で使用中の既存のキーマップを操作すると、 問題を引き起こすことがある。 たとえば、global-mapに適用するとEmacsをほとんど使用不能にしてしまう。

多くの場合、テキストの挿入が必要なくバッファを読み出し専用で使う rmailやdiredなどのモードのローカルキーマップの初期化に suppress-keymapを使う。 ファイルemacs/lisp/dired.elから持ってきた例を示す。 これは、diredモード用のローカルキーマップの設定方法である。

(setq dired-mode-map (make-keymap))
(suppress-keymap dired-mode-map)
(define-key dired-mode-map "r" 'dired-rename-file)
(define-key dired-mode-map "\C-d" 'dired-flag-file-deleted)
(define-key dired-mode-map "d" 'dired-flag-file-deleted)
(define-key dired-mode-map "v" 'dired-view-file)
(define-key dired-mode-map "e" 'dired-find-file)
(define-key dired-mode-map "f" 'dired-find-file)
...


Node:Key Binding Commands, Next:, Previous:Changing Key Bindings, Up:Keymaps

キーをバインドするためのコマンド

本節では、キーのバインディングを変更する 便利で対話的なインターフェイスについて述べます。 これらは、define-keyを呼び出して動作します。

単純なカスタマイズのために ファイル.emacsglobal-set-keyをしばしば使います。 たとえば、

(global-set-key "\C-x\C-\\" 'next-line)

(global-set-key [?\C-x ?\C-\\] 'next-line)

(global-set-key [(control ?x) (control ?\\)] 'next-line)

は、1行下がるようにC-x C-\を再定義します。

(global-set-key [M-mouse-1] 'mouse-set-point)

は、メタキーを押し下げながらマウスの第1ボタン(左端)をクリックすると クリック位置にポイントを設定するように再定義します。

global-set-key key definition コマンド
この関数は、現在のグローバルキーマップにおいて keyのバインディングをdefinitionと設定する。
(global-set-key key definition)
==
(define-key (current-global-map) key definition)

global-unset-key key コマンド
この関数は、現在のグローバルキーマップから keyのバインディングを削除する。

この関数の1つの用途は、 keyに非プレフィックスのバインディングがあると再定義できないため、 keyをプレフィックスとして使う長いキーを定義する前準備である。 たとえば、つぎのとおり。

(global-unset-key "\C-l")
    => nil
(global-set-key "\C-l\C-l" 'redraw-display)
    => nil

この関数は単にdefine-keyを使って実装してある。

(global-unset-key key)
==
(define-key (current-global-map) key nil)

local-set-key key definition コマンド
この関数は、現在のローカルキーマップにおいて keyのバインディングをdefinitionと設定する。
(local-set-key key definition)
==
(define-key (current-local-map) key definition)

local-unset-key key コマンド
この関数は、現在のローカルキーマップから keyのバインディングを削除する。
(local-unset-key key)
==
(define-key (current-local-map) key nil)


Node:Scanning Keymaps, Next:, Previous:Key Binding Commands, Up:Keymaps

キーマップの走査

本節では、ヘルプ情報を表示するために 現在のキーマップをすべて走査する関数について述べます。

accessible-keymaps keymap &optional prefix Function
この関数は、keymapから(0個以上のプレフィックスキーにより)辿れる すべてのキーマップのリストを返す。 その値は、(key . map)の形の要素から成る 連想リストである。 ここで、keyはプレフィックスキーであり、 keymap内でのその定義はmapである。

連想リスト内での要素の順番は、keyの長さが増える順である。 指定したキーマップkeymapはプレフィックスのイベントなしに参照できるので、 最初の要素はつねに("" . keymap)である。

prefixを与える場合、それはプレフィックスキー列であること。 すると、accessible-keymapsは、 prefixで始まるプレフィックスに対応したサブマップのみを含める。 それらの要素は、(accessible-keymaps)の値と同じに見えるが、 違いは、いくつかの要素が省略されることである。

つぎの例では、返された連想リストにおいては、 ^[と表示されたキー<ESC>はプレフィックスキーであり、 その定義は疎なキーマップ (keymap (83 . center-paragraph) (115 . foo))であることを表す。

(accessible-keymaps (current-local-map))
=>(("" keymap
      (27 keymap   ; Note this keymap for <ESC> is repeated below.
          (83 . center-paragraph)
          (115 . center-line))
      (9 . tab-to-tab-stop))

   ("^[" keymap
    (83 . center-paragraph)
    (115 . foo)))

つぎの例では、C-hは、 疎なキーマップ(keymap (118 . describe-variable)...)を 使うプレフィックスキーである。 別のプレフィックスC-x 4は、 変数ctl-x-4-mapの値でもあるキーマップを使う。 イベントmode-lineは、 ウィンドウの特別な箇所におけるマウス操作を表すための 疑似イベントの1つである。

(accessible-keymaps (current-global-map))
=> (("" keymap [set-mark-command beginning-of-line ...
                   delete-backward-char])
    ("^H" keymap (118 . describe-variable) ...
     (8 . help-for-help))
    ("^X" keymap [x-flush-mouse-queue ...
     backward-kill-sentence])
    ("^[" keymap [mark-sexp backward-sexp ...
     backward-kill-word])
    ("^X4" keymap (15 . display-buffer) ...)
    ([mode-line] keymap
     (S-mouse-2 . mouse-split-window-horizontally) ...))

実際に表示されるキーマップはこれらだけとは限らない。

where-is-internal command &optional keymap firstonly noindirect Function
この関数は、コマンドwhere-is (see Help)が使う サブルーティンである。 キーマップにおいてcommandにバインドされた (任意長の)キー列のリストを返す。

引数commandは任意のオブジェクトであり、 キーマップ項目とはeqで比較する。

keymapnilであると、 overriding-local-mapを無視 (つまり、その値はnilとみな)して、 現在活性なキーマップを使う。 keymapnil以外であると、 keymapとグローバルキーマップから辿れるキーマップを使う。

通常、keymapに対する式にはoverriding-local-mapを使うのが 最良である。 そうすると、where-is-internalは正確に活性なキーマップを走査する。 グローバルキーマップのみを走査するには、 keymapとして(keymap)(空のキーマップ)を渡す。

firstonlynon-asciiであると、 戻り値は、可能なキー列のリストではなく、 最初にみつかったキー列を表す1つの文字列である。 firstonlytであると、 値は最初のキー列であるが、 ASCII文字(あるいはASCII文字のメタ変種)のみから成るキー列が 他のキー列より優先される。

noindirectnil以外であると、 where-is-internalは間接項目を辿らない。 これにより、間接項目そのものを探すことができる。

(where-is-internal 'describe-function)
    => ("\^hf" "\^hd")

describe-bindings &optional prefix コマンド
この関数は、現在のすべてのキーバインディングの一覧を作成し、 *Help*という名前のバッファに表示する。 テキストはモードごとにまとめられ、 マイナモード、メジャーモード、グローバルバインディングの順である。

prefixnil以外であると、それはプレフィックスキーであること。 そうすると、prefixで始まるキーのみの一覧を作る。

一覧では、メタ文字は、<ESC>に続けて対応する非メタ文字で表す。

連続したASCIIコードの一連の文字が同じ定義である場合には、 それらをまとめてfirstchar..lastcharと表示する。 この場合、どの文字であるか理解するには、 ASCIIコードを知っている必要がある。 たとえば、デフォルトのグローバルキーマップでは、 <SPC>.. ~の文字が1行に表示される。 <SPC>はASCIIコード32、~ASCIIコード126であり、 そのあいだには普通の印字文字(英文字、数字文字、句読点文字など)が すべて含まれる。 これらの文字はすべてself-insert-commandにバインドされている。


Node:Menu Keymaps, Previous:Scanning Keymaps, Up:Keymaps

メニューキーマップ

キーマップは、キーボードのキーやマウスボタンに対するバインディングに加えて メニューも定義できます。


Node:Defining Menus, Next:, Up:Menu Keymaps

メニューの定義

キーマップに全面プロンプト文字列(overall prompt string)、 つまり、キーマップの要素として文字列が現れれば、 メニューとして使えます。 その文字列でメニューの目的を記述します。 プロンプト文字列を持ったキーマップを作成するもっとも簡単な方法は、 make-keymapmake-sparse-keymap(see Creating Keymaps)を 呼ぶときに、引数として文字列を指定します。

メニュー上での項目の順番は、 キーマップ内のバインディングの順番と同じです。 define-keyは、新たなバインディングを先頭に追加するので、 順番を気にするのならば、メニューの底の項目から始めて 上の項目へ向かってメニュー項目の定義を入れます。 既存のメニューに項目を追加する場合には、 define-key-after(see Modifying Menus)を使って メニュー内での位置を指定できます。


Node:Simple Menu Items, Next:, Up:Defining Menus

単純なメニュー項目

メニューキーマップのバインディングを定義する単純で旧式の方法は つぎのとおりです。

(item-string . real-binding)

CARitem-stringは、メニューに表示される文字列です。 3単語までの短いものにし、対応するコマンドの動作を記述します。

つぎのように、ヘルプ文字列となる2つめの文字列も指定できます。

(item-string help-string . real-binding)

現状では、Emacsは実際にはhelp-stringを使いません。 real-bindingを取り出すためにhelp-stringを無視する方法を 知っているだけです。 将来、ユーザーの要望に応じてメニュー項目に対する追加説明として help-stringを使うかもしれません。

define-keyに関する限り、 item-stringhelp-stringは イベントのバインディングの一部分です。 しかし、lookup-keyreal-bindingのみを返し、 キーの実行にはreal-bindingのみが使われます。

real-bindingnilであると、 item-stringはメニューに現れますが、それは選択できません。

real-bindingがシンボルであり、 その属性menu-enablenil以外であると、 当該属性は、メニュー項目を活性にするかどうかを制御する式です。 Emacsは、メニューを表示するためにキーマップを使うたびに、 その式を評価し、式の値がnil以外である場合に限り、 当該メニュー項目をオンにします。 メニュー項目がオフであると、『薄く』表示し、それは選択できません。

メニューバーでは、読者がメニューを見るたびにどの項目がオンであるかを 再計算しません。 Xツールキットがあらかじめメニューの木構造全体を必要とするからです。 メニューバーの再計算を強制するには、 force-mode-line-updateを呼び出します。 (see Mode Line Format)。

メニュー項目には、同じコマンドを起動する等価なキーボードのキー列が (あれば)表示されていることに気づいたと思います。 再計算の時間を節約するために、 メニューの表示では、この情報をつぎのように バインディングの部分リストに隠し持っています。

(item-string [help-string] (key-binding-data) . real-binding)

読者は、メニュー項目にこれらの部分リストを入れないでください。 それらはメニューの表示で自動的に計算されます。 冗長になるので、項目の文字列には、等価なキーボード入力を 含めないでください。


Node:Extended Menu Items, Previous:Alias Menu Items, Up:Defining Menus

拡張メニュー項目

拡張形式のメニュー項目は、より柔軟性があり、 単純な形式より見通しがよい代替方法です。 それらは、シンボルmenu-itemで始まるリストから成り