Next: , Previous: Classifying Lists, Up: Forms


8.2.4 シンボルの関数間接

リストの先頭要素がシンボルであると、 評価処理ではシンボルの関数セルを調べ、 もとのシンボルのかわりにその内容を使います。 その内容が別のシンボルであると、 シンボルの関数間接(symbol function indirection)と呼ばれる この処理をシンボルでないものを得るまで繰り返します。 シンボルの関数セルに格納された関数名としてのシンボルの使い方について 詳しくは、See Function Names

この処理の結果、無限ループになる場合もあります。 つまり、シンボルの関数セルが同じシンボルを指している場合です。 あるいは、シンボルの関数セルが空の場合もありえます。 その場合、サブルーティンsymbol-functionは、 エラーvoid-functionを通知します。 いずれの場合でもなければ、最終的にはシンボルでないものを取得し、 それは関数などの適切なオブジェクトであるはずです。

より正確にいえば、Lisp関数(ラムダ式)、バイトコード関数、 基本関数、Lispマクロ、スペシャルフォーム、自動ロードオブジェクトの いずれかを取得しているはずです。 これらの各種類ごとに、以下の1つ1つの節で説明します。 オブジェクトがこれらのいずれの型でもない場合には、 エラーinvalid-functionを通知します。

つぎの例は、シンボルの関数間接の処理を図示したものです。 fsetを使ってシンボルの関数セルに設定し、 symbol-functionを使って関数セルの内容を取り出します (see Function Cells)。 具体的には、シンボル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そのものを返す。

Lispでindirect-functionを定義するとつぎのようになる。

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