Next: 関数フォームの評価, Previous: リストフォームの分類, Up: フォームの種類 [Contents][Index]
リストの最初の要素がシンボルなら、評価はそのシンボルの関数セルを調べて、元のシンボルの代わりに関数セルの内容を使用します。その内容が他のシンボルなら、シンボルではないものが得られるまでこのプロセスが繰り返されます。このプロセスのことをシンボル関数インダイレクション(symbol function indirection: indirectionは間接の意)と呼びます。シンボル関数インダイレクションについての情報は関数の命名を参照してください。
このプロセスの結果、シンボルの関数セルが同じシンボルを参照する場合には、無限ループを起こす可能性があります。それ以外なら最終的には非シンボルにたどりつき、それは関数か他の適切なオブジェクトである必要があります。
適切なオブジェクトとは、より正確にはLisp関数(ラムダ式)、バイトコード関数、プリミティブ関数、Lispマクロ、スペシャルフォーム、またはオートロードオブジェクトです。これらそれぞれの型については以降のセクションで説明します。これらの型以外のオブジェクトならEmacsはinvalid-function
エラーをシグナルします。
以下の例はシンボルインダイレクションのプロセスを説明するものです。わたしたちはシンボルの関数セルへの関数のセットにfset
、関数セルの内容(関数セルの内容へのアクセスを参照)の取得にsymbol-function
を使用します。具体的にはfirst
の関数セルにシンボルcar
を格納して、シンボルfirst
をerste
の関数セルに格納します。
;; この関数セルのリンクを構築する:
;; ------------- ----- ------- -------
;; | #<subr car> | <-- | car | <-- | first | <-- | erste |
;; ------------- ----- ------- -------
(symbol-function 'car) ⇒ #<subr car>
(fset 'first 'car) ⇒ car
(fset 'erste 'first) ⇒ first
(erste '(1 2 3)) ; erste
により参照される関数を呼び出す
⇒ 1
対照的に、以下の例ではシンボル関数インダイレクションを使用せずに関数を呼び出しています。なぜなら1番目の要素はシンボルではなく、無名Lisp関数(anonymous Lisp function)だからです。
((lambda (arg) (erste arg)) '(1 2 3)) ⇒ 1
関数自身を実行するとその関数のbodyを評価します。ここではerste
を呼び出すとき、シンボル関数インダイレクションが行なわれています。
このフォームが使用されるのは稀であり、現在では推奨されていません。かわりに以下のように記述するべきです:
(funcall (lambda (arg) (erste arg)) '(1 2 3))
または単に
(let ((arg '(1 2 3))) (erste arg))
ビルトイン関数のindirect-function
は、明示的にシンボル関数インダイレクションを処理するための簡単な方法を提供します。
この関数はfunctionが意味するものを関数としてリターンする。functionがシンボルならfunctionの関数定義を探して、その値で最初からやり直す。functionがシンボルでなければfunction自身をリターンする。
この関数は最終的なシンボルがバインドされていなければnil
をリターンする。特定のシンボル内にループがあれば、この関数はcyclic-function-indirection
エラーをシグナルする。
オペション引数noerrorは廃れており、後方互換のためだけのもので効果はない。
以下はLispでindirect-function
を定義する例である:
(defun indirect-function (function) (if (and function (symbolp function)) (indirect-function (symbol-function function)) function))