次: , 前: Anonymous Functions, 上: Functions


11.8 関数セルの内容の参照

シンボルの関数定義(function definition)とは、 シンボルの関数セルに格納されたオブジェクトです。 ここで説明する関数は、シンボルの関数セルを参照したり、調べたり、 設定したりします。

Function Indirectionの関数indirect-functionも参照してください。

— 機能: symbol-function symbol

これは、symbolの関数セルのオブジェクトを返す。 シンボルの関数セルが空であると、エラーvoid-functionを通知する。

この関数は、返すオブジェクトが正しい関数であるかどうか検査しない。

          (defun bar (n) (+ n 2))
               => bar
          (symbol-function 'bar)
               => (lambda (n) (+ n 2))
          (fset 'baz 'bar)
               => bar
          (symbol-function 'baz)
               => bar
     

シンボルに一度も関数定義を与えていないと、 そのシンボルの関数セルは(void)であるといいます。 いいかえれば、関数セルにはどんなLispオブジェクトも入っていません。 そのようなシンボルを関数として呼び出そうとすると、 エラーvoid-functionを通知します。

空(void)は、nilやシンボルvoidと違うことに注意してください。 シンボルnilvoidもLispオブジェクトであり、 それらは他のオブジェクトと同様に関数セルに格納できます (そして、それらをdefunで定義しておけば、正しい関数である)。 空の関数セルには、どんなオブジェクトも含まれていません。

シンボルの関数定義が空かどうかはfboundpで調べることができます。 シンボルに関数定義を与えたあとでも、 fmakunboundを使ってふたたび空にできます。

— 機能: fboundp symbol

この関数は、シンボルの関数セルにオブジェクトが入っていればtを返し、 さもなければnilを返す。 オブジェクトが正しい関数であるかどうか検査しない。

— 機能: fmakunbound symbol

この関数はsymbolの関数セルを空にする。 これ以降にこのセルを参照しようとすると、 エラーvoid-functionを引き起こす。 (Void Variablesmakunboundも参照)。

          (defun foo (x) x)
               => foo
          (foo 1)
               =>1
          (fmakunbound 'foo)
               => foo
          (foo 1)
          error--> Symbol's function definition is void: foo
     
— 機能: fset symbol definition

この関数は、symbolの関数セルにdefinitionを格納する。 結果はdefinitionである。 通常、definitionは関数か関数名であるべきだが、 そうであるかどうか検査しない。 引数symbolは通常どおり評価される引数である。

この関数の普通の3つの使い方はつぎのとおり。

これらの使用例を示す。

          
          ;; fooの定義をold-fooに保存する
          (fset 'old-foo (symbol-function 'foo))
          
          
          
          ;; シンボルcarxfirstの関数定義にする
          ;; (これには、fsetよりdefaliasのほうがよい)
          (fset 'xfirst 'car)
               => car
          (xfirst '(1 2 3))
               => 1
          (symbol-function 'xfirst)
               => car
          (symbol-function (symbol-function 'xfirst))
               => #<subr car>
          
          
          ;; 名前付きのキーボードマクロを定義する
          (fset 'kill-two-lines "\^u2\^k")
               => "\^u2\^k"
          
          
          ;; 他の関数を変更する関数
          (defun copy-function-definition (new old)
            "Define NEW with the same function definition as OLD."
            (fset new (symbol-function old)))
     

既存の関数定義を拡張する関数を書くときには、 つぎのような常套句を使うこともあります。

     (fset 'old-foo (symbol-function 'foo))
     (defun foo ()
       "Just like old-foo, except more so."
       (old-foo)
       (more-so))

fooが自動ロードと定義されていると、これは正しく動作しません。 そのような場合には、fooold-fooを呼び出すと、 Lispはファイルをロードしてold-fooを定義しようとします。 しかし、これはold-fooではなくfooを定義するので、 正しい結果を得られません。 この問題を回避する唯一の方法は、 fooの古い定義を移すまえに、確実にファイルをロードしておくことです。

しかし、別の箇所で定義された関数を再定義するLispファイルに対しては、 いずれにしても、これではモジュール化も見通しもよくありません。 アドバイズ機能(see Advising Functions)を使えば、見通しがよくなります。