Next: , Previous: , Up: Forms   [Contents][Index]


9.2.4 シンボル関数インダイレクション

リストの最初の要素がシンボルなら、評価はそのシンボルの関数セルを調べて、元のシンボルの代わりに関数セルの内容を使用します。その内容が他のシンボルなら、シンボルではないものが得られるまでこのプロセスが繰り返されます。このプロセスのことをシンボル関数インダイレクション(symbol function indirection: indirectionは間接の意)と呼びます。シンボル関数インダイレクションについての情報はFunction Namesを参照してください。

このプロセスの結果、シンボルの関数セルが同じシンボルを参照する場合には、無限ループを起こす可能性があります。それ以外なら最終的には非シンボルにたどりつき、それは関数か他の適切なオブジェクトである必要があります。

適切なオブジェクトとは、より正確にはLisp関数(ラムダ式)、バイトコード関数、プリミティブ関数、Lispマクロ、スペシャルフォーム、またはオートロードオブジェクトです。これらそれぞれの型については以降のセクションで説明します。これらの型以外のオブジェクトならEmacsはinvalid-functionエラーをシグナルします。

以下の例はシンボルインダイレクションのプロセスを説明するものです。わたしたちはシンボルの関数セルへの関数のセットにfset、関数セルの内容(Function Cellsを参照)の取得にsymbol-functionを使用します。具体的にはfirstの関数セルにシンボルcarを格納して、シンボル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

対照的に、以下の例ではシンボル関数インダイレクションを使用せずに関数を呼び出しています。なぜなら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: indirect-function function &optional noerror

この関数はfunctionが意味するものを関数としてリターンする。functionがシンボルならfunctionの関数定義を探して、その値で最初からやり直す。functionがシンボルでなければfunction自身をリターンする。

この関数は最終的なシンボルがバインドされていなければnilをリターンする。特定のシンボル内にループがれば、この関数はcyclic-function-indirectionエラーをシグナルする。

オペション引数noerrorは廃れており、後方互換のためだけのもので効果はない。

以下はLispでindirect-functionを定義する例である:

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