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

8. 評価

Emacs Lisp式の評価(evaluation)は、 Lispインタプリタ(Lisp interpreter)が行ないます。 Lispインタプリタは、Lispオブジェクトを入力として受け取り、 式としての値(value as an expression)を計算するプログラムです。 評価方法はオブジェクトのデータ型に依存します。本章に述べる規則にしたがいます。 インタプリタはプログラムの一部分を評価するために自動的に実行されますが、 Lispプリミティブevalを明示的に呼び出すことでも実行できます。

評価を目的とするLispオブジェクトを式(expression)あるいは 形式(form)と呼びます。式がデータ・オブジェクトであって、 単なるテキストではないということは、 Lispのような言語と典型的プログラミング言語との間の 根本的な違いの一つです。どんなLispオブジェクトも評価できますが、実際には数、 シンボル、リスト、文字列だけが非常に頻繁に評価されます。

Lisp式を読み込み、その後その式を評価するということは、ごく普通に行なわれ ますが、読込みと評価は別の行為であり、いずれも単独で行なうことができます。 読込みそれ自体は何も評価しません。 それは、Lispオブジェクトの印字表現をオブジェクト自身に変換するものです。 このオブジェクトが評価すべき形式であるかどうか、あるいは全く異なる目的 に使うものなのかどうかということは、readの呼び手次第です。 See section 入力関数

評価とキー解釈とを混同しないでください。 エディタのコマンド・ループは、アクティブなキーマップを使ってキーボード入力を コマンド(対話的に呼び出せる関数)に変換し、その後call-interactivelyを 使ってそのコマンドを起動します。 コマンドがLispで書かれていたならばコマンドの実行自身が評価を含みますが、それ はコマンドのキー解釈自身の一部ではありません。See section コマンド・ループ

評価は再帰的処理です。いいかえると、形式の評価は形式の一部分を評価 するためにevalを呼び出すかもしれないということです。たとえば、関 数呼び出の評価では最初に関数呼出しの各引数の評価を行ない、その後で関数本体 中の各形式を評価します。形式(car x)の評価を考えてみると、部分形式 xを最初に再帰的に評価しなければ、その値を関数carの引数として 渡すことができません。

関数呼出しの評価は、最終的には、そこで指定された関数を呼び出します。 See section 関数。関数の実行は、それ自体がその関数定義の評価による ものかも知れません。あるいは、関数はCで実装されたLispのプリミティブかも 知れませんし、バイトコンパイルされた関数(see section バイトコンパイル) かも知れません。

形式の評価は、全てのLisp変数の現在の値と現在の束縛からなる 環境(environment)と呼ばれる状況の中で行なわれます。 (9) その変数に新しい束縛を与える場合を除いて、形式が変数を参照するときは常に 現在の環境中で束縛された値が使われます。See section 変数

形式の評価は、変数の束縛によって、再帰的評価のための新たな環境を作るこ とがあります(see section ローカル変数)。これら環境は一時的なもので、 形式の評価完了時には消えてしまいます。形式は永続的な変更を作ることもあります。 このような変更を副作用(side effect)と呼びます。副作用を起こす形式の例は、 (setq foo 1)です。

各種の形式に対する評価が何であるかということの詳細を以下に説明します (see section 形式の種類)。


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

8.1 Eval

ほとんどの場合、実行中のプログラムの現れた場所で、形式は自動的に評価さ れます。まれに、実行時に計算される形式を評価するコードを書く必要に迫られるか も知れません。編集中のテキストから形式を読み取った後や、属性リストから 形式を取り出した後のような場合です。このような場合にeval関数 を使います。

注意!: 一般的には、データ構造に格納された式を評価するよりも、 データ構造に格納された関数を呼び出す方が、きれいかつ柔軟です。 関数を使うと、情報を引数として渡すことができます。

この節で説明する関数と変数には、形式を評価するもの、評価処理の制限を指定す るもの、最近返された値を記録するものがあります。ファイルをロードすると、 やはり評価を行ないます(see section ロード)。

Function: eval form

評価を行なう基本の関数です。現在の環境のformを評価し、結果を返します。 評価がどのように処理されるかは、オブジェクトの型に依存します(see section 形式の種類)。

evalは関数なので、eval呼出しに現れる引数の式は2回評価され ます。そのうち1回はeval呼出し前の準備として、 もう1回はeval関数自身によって行なわれます。例を挙げます:

 
(setq foo 'bar)
     ⇒ bar
(setq bar 'baz)
     ⇒ baz
;; eval は引数bar(fooの値である)を受取る。
(eval foo)
     ⇒ baz
(eval 'foo)
     ⇒ bar

eval呼出しの、ある時点での有効回数は、 max-lisp-eval-depth(以下参照)によって制限されます。

Command: eval-region start end &optional stream

この関数は、カレント・バッファの位置startendの範囲で定められる リージョン内の全形式を評価します。 リージョンから形式を読み込んで、その形式に対してevalを呼び出すことを、 リージョンの終わりに達するかハンドルされないエラーが通知されるまで続けます。

streamを与えると、評価中はstandard-outputstreamに束縛します。

変数load-read-functionを使うと、eval-regionが式を読み込むときに readの代わりに使う関数を指定することもできます。 See section プログラムでロードする方法

eval-regionは常にnilを返します。

Command: eval-current-buffer &optional stream

この関数は、バッファ全体に対して実行することを除けばeval-regionと 同じです。

Variable: max-lisp-eval-depth

この変数は、eval, apply, funcall呼出しにおいて許され るネストの深さの最大値を定義します。これを超えると、(エラー・メッセージ "Lisp nesting exceeds max-lisp-eval-depth"をともなう)エラーが 通知されます。この数には、これらの関数の内部的使用や、関数呼出しの引数や 関数本体の形式の再帰的評価も勘定に入れます。前者には、Lisp式の形で 書かれた関数の呼出しも含まれます。

この制限は、制限を超えたときにそれを表すエラーを出力することで、間違って定義 された関数の無限再帰をLispで回避するための一つの方法です。

この変数のデフォルト値は200です。設定した値が100未満のときにその値に達した場合 は、Lispは値を100に再設定します。

max-specpdl-size が別のネストの制限を与えます。See section ローカル変数

Variable: values

この変数の値は、(ミニバッファを含む)バッファから読み込まれ、評価され、 印字された全ての式が返した値のリストです。その要素は最近のものほど前に 来るように並んでいます。

 
(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)
;; これで新しい要素を一つ追加したことになるので、
;;   全ての要素は一つ後ろに動く。
(nth 1 values)
     ⇒ (A 3 t)
;; この例の実行前には2番目に新しかった
;;   要素を取り出す。
(nth 3 values)
     ⇒ 1

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

8.2 形式の種類

評価されることを目的とするLispオブジェクトを形式(form)と呼びます。 Emacsがどのように形式を評価するかは、そのデータ型に依存します。 Emacsは評価方法の違いで形式を3種類に分けます。 シンボル、リスト、および「ほかの全ての型」です。 この節では、自己評価型形式である「ほかの全ての型」から始めて、 これら3種すべてについて説明します。


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

8.2.1 自己評価型形式

自己評価型形式(self-evaluating form)とは、リストや シンボルではない形式のことをいいます。自己評価型形式を 評価するとそれら自身になります。その評価結果は評価したオブジェクトと 同一になります。それゆえ、数25は25と評価され、文字列"foo"は 文字列"foo"と評価されます。同様に、ベクタの評価ではベクタ要素の 評価は起こりません。内容の変わらない同じベクタが返ります。

 
'123               ; オブジェクトを評価抜きで見る。
     ⇒ 123
123                ; 普通に評価する(結果は同じ)。
     ⇒ 123
(eval '123)        ; 「手作業で」評価する ---結果は同じ。
     ⇒ 123
(eval (eval '123)) ; 2回評価しても何も変わらない。
     ⇒ 123

数、文字、文字列、ベクタさえもこれらが自己評価型である利点を活かして、 Lispコードに当たり前に書いています。けれどもリード構文がない型に対してこの ように書くということは普通は行ないません。なぜならそういったものをテキストで 書く方法がないためです。こういった型を含むLisp式をLispプログラムという 手段によって構築することは可能です。例を挙げます:

 
;; バッファ・オブジェクトを含む式を作る。
(setq buffer (list 'print (current-buffer)))
     ⇒ (print #<buffer eval.texi>)
;; それを評価する。
(eval buffer)
     -| #<buffer eval.texi>
     ⇒ #<buffer eval.texi>

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

8.2.2 シンボル形式

シンボルが評価されるときは、変数として扱われます。結果は、あるとすれば 変数の値です。値がない場合(その値セルがvoidの場合)は、 エラーが通知されます。変数の使い方についてこれ以上の話は、 変数を参照してください。

以下の例では、シンボルの値をsetqで設定します。その後シンボルを 評価し、setqが格納した値を取り戻します。

 
(setq a 123)
     ⇒ 123
(eval 'a)
     ⇒ 123
a
     ⇒ 123

niltというシンボルは、特別な扱いを受けます。その結果、 nilの値は常にnilであり、tの値は常にtになります。 これらをほかの値に設定することも束縛することもできません。したがって、たとえ evalがこれらをほかのシンボルのように扱ったとしても、この二つのシンボ ルは自己評価型形式のように振舞います。


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

8.2.3 リスト形式の分類

リストという形式は、それが空でないならば、その最初の要素によって、 関数呼出しか、マクロ呼出しか、特殊形式かのいずれかになります。 これら3種の形式は、以下に述べるように異なる方法で評価されます。 リストの残りの要素は、関数、マクロ、特殊形式いずれかの引数(argument)を 構成します。

空ではないリストの評価の最初の手順は、その第1要素の検査です。この 要素だけが、そのリストがどの種類の形式であるのかということと、リストの残 りがどのように処理されるかということを決定します。 Lispの方言によっては、たとえばSchemeでは評価するのですが、 Emacs Lispでは第1要素は評価しません


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

8.2.4 シンボル関数間接参照

リストの第1要素がシンボルならば、評価においてはそのシンボルの関数セ ルを検査し、その中身を元のシンボルの代わりに使用します。 その中身がほかのシンボルならば、このシンボル関数間接参照 (symbol function indirection)と呼ぶ処理を非シンボルを得るまで繰り返します。 シンボルの関数セルに格納された関数の名前として、 そのシンボルを使うことについてのこれ以上の話は、See section 関数の命名

この処理の結果として無限ループになることもあります。それは、 シンボルの関数セルが同じシンボルを参照しているときに起こります。 あるいは、シンボルがvoidな関数セルを持ち、そのためにサブルーチン symbol-functionvoid-functionエラーを通知するかも知れません。 このいずれも起こらない場合は、最終的には非シンボルを得ます。 その非シンボルは関数またはほかの適当なオブジェクトになっているはずです。

もっと精確に書くと、Lisp関数(ラムダ式)、バイトコード関数、 プリミティブ関数、Lispマクロ、特殊形式、自動ロード・オブジェクトのいずれかに なっていないとおかしいでしょう。 これらの型のそれぞれは以下のどれかの節で説明します。オブジェクトがこれ ら型のいずれでもない場合、invalid-functionエラーが通知されます。

以下の例は、シンボル間接参照処理を図解しています。fsetを使っ てシンボルの関数セルを設定し、symbol-functionで先の関数セルの内容 を取り出しています(see section 関数セルの内容へのアクセス)。具体的には、シンボル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は、明示的に関数のシンボル関数間接参照 を簡単に行なう方法を提供しています。

Function: indirect-function function

この関数は、functionの関数としての意味を返します。functionが シンボルならば、functionの関数定義を見つけ、その値を用いて最初から やり直します。functionがシンボルではないならば、function自身を 返します。

 
(defun indirect-function (function)
  (if (symbolp function)
      (indirect-function (symbol-function function))
    function))

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

8.2.5 関数形式の評価

評価しているリストの第1要素がLisp関数オブジェクトの場合、 バイトコード・オブジェクトの場合、あるいはプリミティブ関数オブジェクトの 場合は、そのリストは関数呼出し(function call)です。たとえば、 これは関数+の呼出しです:

 
(+ 1 x)

関数呼出しを評価する第1手順は、残りのリスト要素を左から右に評価する ことです。結果は実引数の値であり、一つの値がリスト要素一つに対応します。 次の手順はこの引数のリストを持って関数を呼び出すことで、事実上関数 applyを使用します(see section 関数の呼出し)。 この関数がLispで書かれていたならば、実引数で関数の仮引数を束縛します (see section ラムダ式)。 その後関数本体内の形式が順序どおりに評価され、最後の本体形式が関数呼出しの 値になります。


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

8.2.6 Lispマクロの評価

評価中のリストの第1要素がマクロ・オブジェクトならば、リストは マクロ呼出し(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 section マクロ


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

8.2.7 特殊形式

特殊形式(special form)とはその引数の全てが評価されないように 設計された関数です。特殊形式のほとんどが、制御構造を定義したり変数の束縛、 関数がやれないこと、を行ないます。

特殊形式のそれぞれが固有の規則を持っていて、どの引数を評価し、 どの引数は評価しないで使うかを決めます。特定の引数が評価されるか否かが、 ほかの引数を評価した結果に依存することもあります。

and

see section 条件を結合するための構文要素

catch

see section 明示的な非局所脱出: catchthrow

cond

see section 条件分岐

condition-case

see section エラーをハンドルするコードの記述

defconst

see section グローバル変数の定義

defmacro

see section マクロの定義

defun

see section 関数の定義方法

defvar

see section グローバル変数の定義

function

see section 匿名関数

if

see section 条件分岐

interactive

see section 対話的呼出し

let
let*

see section ローカル変数

or

see section 条件を結合するための構文要素

prog1
prog2
progn

see section 順次実行

quote

see section quoteする

save-excursion

see section 脱線

save-restriction

see section ナローイング

save-window-excursion

see section ウィンドウ構成

setq

see section 変数の値を変更する方法

setq-default

see section バッファローカルな束縛の作成と削除

track-mouse

see section マウスの追跡

unwind-protect

see section 非局所脱出

while

see section 繰り返し

with-output-to-temp-buffer

see section 一時表示

Common Lisp注意書き: GNU Emacs LispとCommon Lispとの特殊形式の 比較をします。setq, if, catchは、Emacs Lispと Common Lispとの双方において特殊形式です。defunはEmacs Lispでは 特殊形式ですが、Common Lispではマクロです。save-excursionは Emacs Lispにおいては特殊形式ですが、Common Lispには存在しません。 throwはCommon Lispでは特殊形式(複数の値をthrowできるようにするため) ですが、Emacs Lispでは関数です(複数の値は持たない)。


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

8.2.8 自動ロード

自動ロード(autoload)機能によって、まだEmacsにその定義が ロードされてないような関数やマクロを呼び出すことができます。これによって、 どのファイルがその定義を含むかを指定します。自動ロード・オブジェクトが シンボルの関数定義として現れたとき、そのシンボルを関数として呼び出すことで 自動的に指定されたファイルがロードされます。その後、ファイルからロードされた 実際の定義を呼び出します。See section 自動ロード


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

8.3 quoteする

特殊形式quoteは、一つの引数を、書かれたとおり、評価をせずに 返します。これによって、定数シンボルやリストなど、 自己評価型ではないオブジェクトをプログラムに含める手段が用意されています (数、文字列、ベクタなど、自己評価型オブジェクトをquoteする必要はありません)。

Special Form: quote object

この特殊形式はobjectを評価せずに返します。

quoteはしょっちゅうプログラムで使われるので、Lispはそれを便利にする リード構文を用意しています。アポストロフィ文字(`'')に続く一つのLisp オブジェクト(リード構文において)は、第1要素がquoteで、2番目の要素 が先のオブジェクトというリストに展開されます。したがって、リード構文'x は、(quote x)の省略形です。

quoteを使う式の例を挙げます:

 
(quote (+ 1 2))
     ⇒ (+ 1 2)
(quote foo)
     ⇒ foo
'foo
     ⇒ foo
''foo
     ⇒ (quote foo)
'(quote foo)
     ⇒ (quote foo)
['foo]
     ⇒ [(quote foo)]

そのほかのquoteを行なう構文要素には、Lispで書かれた匿名ラムダ式が コンパイルされるようになるfunction(see section 匿名関数)、 ほかの部分の計算や置換をする間、リストの一部だけをquoteするために使用する `(see section 逆引用符)があります。


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

This document was generated by Yasutaka SHINDOH on September, 29 2006 using texi2html 1.76.