次: Inline Functions, 前: Anonymous Functions, 上: Functions
シンボルの関数定義(function definition)とは、 シンボルの関数セルに格納されたオブジェクトです。 ここで説明する関数は、シンボルの関数セルを参照したり、調べたり、 設定したりします。
Function Indirectionの関数indirect-functionも参照してください。
これは、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と違うことに注意してください。
シンボルnilもvoidもLispオブジェクトであり、
それらは他のオブジェクトと同様に関数セルに格納できます
(そして、それらをdefunで定義しておけば、正しい関数である)。
空の関数セルには、どんなオブジェクトも含まれていません。
シンボルの関数定義が空かどうかはfboundpで調べることができます。
シンボルに関数定義を与えたあとでも、
fmakunboundを使ってふたたび空にできます。
この関数はsymbolの関数セルを空にする。 これ以降にこのセルを参照しようとすると、 エラー
void-functionを引き起こす。 (Void Variablesのmakunboundも参照)。(defun foo (x) x) => foo (foo 1) =>1 (fmakunbound 'foo) => foo (foo 1) error--> Symbol's function definition is void: foo
この関数は、symbolの関数セルにdefinitionを格納する。 結果はdefinitionである。 通常、definitionは関数か関数名であるべきだが、 そうであるかどうか検査しない。 引数symbolは通常どおり評価される引数である。
この関数の普通の3つの使い方はつぎのとおり。
- あるシンボルの関数定義を別のものにコピーする。 いいかえれば、関数の別名を作る。 (これを新たな名前の定義と考えるならば、
fsetのかわりにdefaliasを使うべきである。 see Defining Functions。)- リストではない関数定義をシンボルに与える。 これは、
defunではできない。 たとえば、fsetを使って、s1に関数定義として 別のシンボルs2を与えることができる。 すると、s1は、s2の現在の定義の別名として働く。 (これをs1の定義と考えるのであれば、 やはり、fsetのかわりにdefaliasを使う。)- 関数を定義したり変更したりする構文で使う。
defunが基本関数でなかったならば、fsetを使って(マクロとして)Lispでdefunを書くことができる。これらの使用例を示す。
;;fooの定義をold-fooに保存する (fset 'old-foo (symbol-function 'foo)) ;; シンボルcarをxfirstの関数定義にする ;; (これには、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が自動ロードと定義されていると、これは正しく動作しません。
そのような場合には、fooがold-fooを呼び出すと、
Lispはファイルをロードしてold-fooを定義しようとします。
しかし、これはold-fooではなくfooを定義するので、
正しい結果を得られません。
この問題を回避する唯一の方法は、
fooの古い定義を移すまえに、確実にファイルをロードしておくことです。
しかし、別の箇所で定義された関数を再定義するLispファイルに対しては、 いずれにしても、これではモジュール化も見通しもよくありません。 アドバイズ機能(see Advising Functions)を使えば、見通しがよくなります。