[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

2. 評価の練習

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=eintro&node=Practicing%20Evaluation"
"intro/評価の練習"へのコメント(無し)

Emacs Lispにおける関数定義の書き方を学ぶまえに、これまでに説明してきた さまざまな式の評価に時間を割いてみるのも有益であろう。 リストの先頭(あるいは唯一)の要素が関数であるようなリストである。 バッファに関する関数は、単純でしかも興味深いので、これらから始めよう。 本節では、それらのいくつかを評価してみる。 他の節では、バッファに関連した数個の別の関数のコードを調べて、 それらがどのように書かれているかを見てみる。

How to Evaluate

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=eintro&node=How%20to%20Evaluate"
"intro/HowtoEvaluate"へのコメント(無し)

Emacs Lispに、カーソルの移動や画面上のスクロールなどの 編集コマンドを与えるたびに、先頭要素が関数である式を評価しているEmacsはこのようにして動いている。

キーをタイプすると、Lispインタープリタに式を評価させることになり、 そのようにして操作しているのである。 テキストをタイプした場合でさえも、Emacs Lispの関数を評価しており、 タイプした文字を単に挿入する関数self-insert-commandを使った 関数を評価しているのである。 キーをタイプすることで評価される関数は、 対話的(interactive)関数とかコマンド(commands)と呼ばれる。 関数を対話的にする方法については、関数定義の書き方の章で例を示す。 See 節 3.3 関数を対話的にする

キーボードコマンドをタイプする以外にも、 式を評価する方法についてはすでに説明した。 すなわち、リストの直後にカーソルを置いてC-x C-eとタイプするのである。 本節の残りでは、この方法を用いる。 これ以外にも式を評価する方法があり、必要に応じて他の節で説明する。

これからの数節で説明する関数は、評価を練習すること以外にも、 それ自体、重要なものである。 これらの関数を学ぶことで、バッファとファイルの違い、 バッファを切り替える方法、バッファ内での位置を調べる方法が明らかになる。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

2.1 バッファ名

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=eintro&node=Buffer%20Names"
"intro/バッファ名"へのコメント(無し)

2つの関数、buffer-namebuffer-file-nameが、 ファイルとバッファの違いを示してくれる。 式(buffer-name)を評価すると、エコー領域にバッファ名が表示される。 (buffer-file-name)を評価すると、 バッファが参照するファイル名がエコー領域に表示される。 通常、(buffer-name)が返す名前は、 そのバッファが参照するファイルの名前と同じであり、 (buffer-file-name)が返す名前はファイルの完全パス名である。

ファイルとバッファは異なる2つの実体である。 ファイルは(削除しない限り)コンピュータに恒久的に記録された情報である。 一方、バッファはEmacsの内部にある情報であり、 (バッファを削除するか)編集作業を終了すると消えてしまう。 通常、バッファにはファイルからコピーした情報が収められている。 これを、バッファがファイルを訪れる(visiting)という。 このコピーを処理したり修正したりしているのである。 バッファを変更しても保存しない限り、ファイルは変更されない。 バッファを保存すると、バッファはファイルにコピーされ、 その結果、恒久的に保存されるのである。

GNU EmacsのInfoを使って読んでいる場合には、 つぎのそれぞれの式の直後にカーソルを置いてC-x C-eとタイプすれば、 それぞれの式を評価できる。

 
(buffer-name)

(buffer-file-name)

筆者がこれを行うと、(buffer-name)を評価して返される値は `"introduction.texinfo"'であり、 (buffer-file-name)を評価して返される値は `"/gnu/work/intro/introduction.texinfo"'である。 前者はバッファ名であり、後者はファイル名である (各式には括弧があるので、Lispインタープリタはbuffer-namebuffer-file-nameを関数として扱う。 括弧がないと、インタープリタは変数としてシンボルを評価しようとする。 See 節 1.7 変 数)。

ファイルとバッファの違いにもかかわらず、 バッファを意味してファイルといったり、その逆のいい方をする場合が多い。 もちろん、ほとんどの人は、「すぐにファイルに保存するバッファを編集している」 というよりは、「ファイルを編集している」という。 その人が何を意図しているかは、ほとんどの場合、文脈から明らかである。 しかし、コンピュータプログラムに関していえば、 コンピュータは人間のように賢くはないので、 つねに違いを心にとめておく必要がある。

ところで、用語「バッファ(buffer)」は、衝突力を弱めるクッションを意味する 語に由来する。 初期のコンピュータでは、ファイルとコンピュータの中央処理装置のあいだの 相互作用のクッションがバッファであった。 ファイルを格納するドラムやテープと中央処理装置とは、互いに大きく異なる 装置であり、それぞれ固有の動作速度で動いていた。 バッファにより、これらが効率よく協調動作することが可能であった。 しだいに、バッファは、中間の一時的な保管場所から、 実際の処理を行う場所へと進展していった。 これは、小さな港が大都市に発展したり、貨物を船に積み込むまえの一時的な保管倉庫 がその重要性のためにビジネスや文化の中心に進展したことに似ている。

すべてのバッファがファイルに関連付けられるわけではない。 たとえば、ファイル名をいっさい指定せずにコマンドemacsだけをタイプして Emacsを開始した場合には、画面にはバッファ`*scratch*'が表示されて Emacsが動き出す。 このバッファはいかなるファイルも訪問していない。 同様に、バッファ`*Help*'にはいかなるファイルも関連付けられていない。

バッファ`*scratch*'に切り替えてから、(buffer-name)と入力して その直後にカーソルを置いてC-x C-eとタイプしてこの式を評価すると、 名前"*scratch*"が返されてエコー領域に表示される。 "*scratch*"がバッファの名前である。 しかし、バッファ`*scratch*'で(buffer-file-name)とタイプして これを評価すると、エコー領域にはnilと表示される。 nilの語源はラテン語の「無(nothing)」を意味する単語であり、 この場合、バッファ`*scratch*'にはいかなるファイルも関連付けられていない ことを意味する (Lispでは、nilは「偽(false)」をも意味し、 空リスト()の同義語でもある)。

バッファ`*scratch*'を使っているときに、 式の評価結果をエコー領域ではなくバッファ`*scratch*'そのものに 表示したい場合には、C-x C-eのかわりにC-u C-x C-eとタイプする。 これにより、式の直後に返された値が表示される。 バッファはつぎのようになる。

 
(buffer-name)"*scratch*"

Infoは読み出し専用なのでバッファの内容を変更できないため、 Infoではこの方法を使えない。 しかし、編集可能なバッファならば、この方法を使える。 コードや(本書のような)文書を書くときには、この機能はとても便利である。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

2.2 バッファの取得

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=eintro&node=Getting%20Buffers"
"intro/バッファの取得"へのコメント(無し)

関数buffer-nameは、バッファの名前を返す。 バッファそのものを取得するには、 別の関数current-bufferが必要である。 この関数をコードで使うと、バッファそのものを取得することになる。

名前とその名前が表すオブジェクトや実体とは互いに異なるものである。 読者自身は読者の名前ではない。 読者は、その名前で他人が参照する「人」である。 読者がGeorgeと話したいと頼んだときに、`G'、`e'、`o'、`r'、 `g'、`e'と文字が書かれたカードを渡されたら、驚くであろうが、 満足はしないであろう。 名前と話をしたいのではなくて、その名前で参照される人と話をしたいのである。 バッファも同様である。 一時的バッファの名前は`*scratch*'であるが、 名前そのものがバッファではない。 バッファそのものを得るにはcurrent-bufferのような関数を使う必要がある。

しかし、多少込み入った事情もある。 ここで試すように、式でcurrent-bufferを評価すると バッファの内容ではなくバッファの表示形式が表示される。 Emacsがこのように動作する理由は2つある。 バッファには数千もの行が含まれることもあるので、 これを簡便に表示するには長すぎる。 また、バッファの内容は同じであっても、名前が異なるバッファもありえるので、 それらを区別できる必要がある。

例を示そう。

 
(current-buffer)

いつものようにこの式を評価すると、 エコー領域には`#'と表示される。 バッファ名ではなく、バッファそのものを表す特殊な表示形式である。

数やシンボルはプログラムに入力できるが、 バッファの表示形式を入力することはできない。 バッファそのものを得る唯一の方法は、 current-bufferのような関数を使うことである。

関連する関数としてother-bufferがある。 これは、現在使用しているバッファの直前に選択していたバッファを返す。 たとえば、バッファ`*scratch*'から現在のバッファに切り替えた場合には、 other-bufferはバッファ`*scratch*'を返す。

つぎの式を評価してみよう。

 
(other-buffer)

エコー領域には、`#'、あるいは、 今のバッファに切り替えるまえのバッファの表示形式が表示される。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

2.3 バッファの切り替え

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=eintro&node=Switching%20Buffers"
"intro/バッファの切り替え"へのコメント(無し)

関数other-bufferの目的は、バッファそのものを引数に必要とする 関数にバッファを与えることである。 別のバッファに切り替えるためother-bufferswitch-to-bufferとを 使ってみよう。

まず、関数switch-to-bufferの概要を説明しておこう。 (buffer-name)を評価するためにInfoからバッファ`*scratch*'へ 切り替えるときには、C-x bとタイプし、ミニバッファに表示された 切り替え先バッファ名のプロンプトに`*scratch*'と入力したであろう。 C-x bとタイプすると、LispインタープリタはEmacs Lispの対話的関数 switch-to-bufferを評価する。 すでに説明したように、Emacsはこのように動作する。 キー列が異なれば、異なる関数を呼び出す、つまり、実行するのである。 たとえば、C-fとタイプするとforward-charを呼び出し、 M-eとタイプするとforward-sentenceを呼び出すなどである。

switch-to-bufferを書いた式に切り替え先のバッファを指定すれば、 C-x bと同じようにバッファを切り替えられる。

たとえば、つぎのLispの式である。

 
(switch-to-buffer (other-buffer))

リストの先頭要素はシンボルswitch-to-bufferであるので、 Lispインタープリタはこれを関数として扱い、それに結び付けられている 命令列を実行する。 しかし、そのまえに、インタープリタはother-bufferが括弧の内側にあることを 検出して、まずそのシンボルを処理する。 other-bufferはこのリストの先頭(かつ唯一の)要素なので、 Lispインタープリタはこの関数を呼び出す。 これは別のバッファを返す。 続いて、インタープリタは、この別のバッファを引数として switch-to-bufferに渡して実行し、そのバッファへ切り替える。 Infoで読んでいる場合には、この式を評価してみてほしい (Infoのバッファに戻るにはC-x b RETとタイプする)。

本書の以降の節のプログラム例では、関数switch-to-bufferよりも 関数set-bufferを多用する。 これは、コンピュータプログラムと人間との違いによるものである。 人間には目があるので、端末画面で作業中のバッファを見ることを期待する。 これは当然のことであり、これ以上説明する必要はなかろう。 一方、プログラムに目はない。 コンピュータプログラムがバッファを処理するときに、 端末画面でバッファが見えている必要はない。

switch-to-bufferは人間向けに考えられたものであり、 異なる2つのことを行う。 Emacsの注意をバッファに向けることと、 ウィンドウに表示するバッファをそのバッファに切り替えることである。 一方、set-bufferは1つのことだけを行い、 コンピュータプログラムの注意をそのバッファに向けるだけである。 画面上のバッファは変更しない (もちろん、コマンドが終了するまでは、何も起こらない)。

ここでは、新たな専門用語呼び出し(call)も使った。 リストの先頭のシンボルが関数であるようなリストを評価すると、 その関数を呼び出すのである。 この用語は、鉛管工を「呼ぶ」とパイプの洩れを修理してくれるのと同じように、 関数は、「呼び出す」と何かを行ってくれる実体であるという考え方からきている。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

2.4 バッファサイズとポイントの位置

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=eintro&node=Buffer%20Size%20&%20Locations"
"intro/バッファサイズとポイントの位置"へのコメント(無し)

最後に、buffer-sizepointpoint-minpoint-max などの比較的単純な関数を見てみよう。 これらにより、バッファのサイズやバッファ内のポイントの位置に関する情報を 得ることができる。

関数buffer-sizeは、カレントバッファのサイズを返す。 つまり、バッファ内の文字の個数を返す。

 
(buffer-size)

いつものように、この式の直後にカーソルを置いてC-x C-eとタイプすれば、 この式を評価できる。

Emacsでは、カーソルの現在位置をポイント(point)と呼ぶ。 式(point)は、バッファの先頭からポイントまでの文字の個数として、 カーソルの位置を返す。 いつものようにつぎの式を評価すると、 バッファ内でのポイントまでの文字数を調べることができる。

 
(point)

筆者の場合、この値は65724であった。 本書の例では、関数pointを多用している。

ポイントの値は、当然であるが、バッファ内での位置に依存する。 ここでつぎの式を評価すると、より大きな数になる。

 
(point)

筆者の場合、ポイントの値は66043となり、 2つの式のあいだには(空白を含めて)319文字あることがわかる。

関数point-minは、pointとほぼ同じであるが、 カレントバッファにおいて取ることが可能なポイントの最小値を返す。 ナロイング(narrowing)していなければ、これは数1である (ナロイング(偏狭化)とは、プログラムなどで操作するバッファの範囲を 制限する機構である。 See 節 6. ナロイングとワイドニング)。 同じように、関数point-maxは、 カレントバッファにおいて取ることが可能なポイントの最大値を返す。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端] [?]

2.5 演習問題

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=eintro&node=Evaluation%20Exercise"
"intro/演習問題"へのコメント(無し)

適当なファイルを読み込み、その中ほどに移動する。 バッファ名、ファイル名、長さ、ファイル内での位置のそれぞれを調べてみよ。


[ << ] [ >> ]           [表紙] [目次] [索引] [検索] [上端 / 下端] [?]