Next: Function Forms, Previous: Classifying Lists, Up: Forms [Contents][Index]
リストの最初の要素がシンボルの場合、評価はそのシンボルの関数セルを調べて、元のシンボルの代わりに、関数セルの内容を使用します。その内容が他のシンボルの場合、シンボルではないものが得られるまで、このプロセスが繰り返されます。このプロセスをシンボル関数インダイレクション(symbol function indirection: indirectionは間接の意)と呼びます。シンボル関数インダイレクションについての情報は、Function Namesを参照してください。
このプロセスの結果、シンボルの関数競るが同じシンボルを参照する場合、無限ループを起こす可能性があります。それ以外は、最終的には非シンボルにたどりつき、これは関数か、他の適切なオブジェクトであるはずです。
より正確に言うと、それはLisp関数(ラムダ式)、バイトコード関数、基本関数、Lispマクロ、スペシャルフォーム、またはオートロードオブジェクトであるべきです。これらの型のそれぞれについては、以降のセクションで説明します。これらの型以外のオブジェクトの場合、emacsはinvalid-function
エラーをシグナルします。
以下の例は、シンボルインダイレクションのプロセスを説明するものです。わたしたちは、シンボルの関数セルに関数をセットするのにfset
、関数セルの内容(Function Cellsを参照してください)を得るために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が意味するものを、関数としてreturnします。functionがシンボルの場合は、functionの関数定義を探して、その値で最初からやり直します。functionがシンボルでない場合は、function自身をreturnします。
この関数は、最後のシンボルがバインドされておらず、オプション引数noerrorが省略されているかnil
の場合は、void-function
エラーをシグナルします。それ以外は、noerrorが非nil
の場合は、最後のシンボルがバインドされていなければnil
をreturnします。
特定のシンボル内にループがある場合、この関数はcyclic-function-indirection
エラーをシグナルします。
以下は、Lispでindirect-function
を定義できるという例です:
(defun indirect-function (function) (if (symbolp function) (indirect-function (symbol-function function)) function))