次: 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)を使えば、見通しがよくなります。