Next: Mapping Functions, Previous: Defining Functions, Up: Functions [Contents][Index]
関数を定義しただけでは、半分しか終わっていません。関数はそれを呼び出す(call) — たとえば実行(run)するまでは、何も行いません。関数のcallは、invocationとしても知られています。
関数を呼び出すもっとも一般的な方法は、リストの評価による方法です。たとえば、リスト(concat "a"
"b")
を評価することにより、関数concat
が引数"a"
と"b"
で呼び出されます。評価については、Evaluationを参照してください。
プログラム内で式としてリストを記述するときは、プログラム内にテキストで、どの関数を呼び出すか、いくつの引数を与えるかを指定します。通常は、これが行いたいことです。どの関数を呼び出すかを、実行時に計算する必要がある場合もあります。これを行うには、関数funcall
を使用します。実行時にいくつの引数を渡すか決定する必要があるときは、apply
を使用します。
funcall
は、関数functionを引数argumentsで呼び出し、functionがreturnした値をreturnします。
funcall
は関数なので、functionを含むすべての引数は、funcall
の呼び出し前に評価されます。これは、呼び出される関数を得るための任意の式を使用できることを意味します。これはまた、funcall
がargumentsに記述した式ではなく、その値だけを見ることを意味します。これらの値はfunction呼び出し中では、2回目は評価されません。funcall
の処理は、関数の通常の呼び出し手続きと似ており、すでに評価された引数は評価されません。
引数functionは、Lisp関数、またはプリミティブ関数でなければなりません。つまりスペシャルフォームやマクロは、“評価されていない”引数式を与えられたときだけ意味があるので、指定することはできません。上述したように、funcall
は最初に指定された評価前の引数を提供することはできません。
(setq f 'list) ⇒ list
(funcall f 'x 'y 'z) ⇒ (x y z)
(funcall f 'x 'y '(z)) ⇒ (x y (z))
(funcall 'and t nil) error→ Invalid function: #<subr and>
これらの例を、apply
の例と比較してみてください。
apply
は、関数functionを引数argumentsで呼び出します。これはfuncall
と同様ですが、1つ違いがあります。argumentsの最後はオブジェクトのリストです。これは1つのリストではなく、個別の引数としてfunctionに渡されます。わたしたちはこれを、apply
がこのリストを展開(spread)(個々の要素が引数となるので)する、と言います。
apply
は、functionを呼び出した結果をreturnします。funcall
と同様、functionはLisp関数かプリミティブ関数でなければなりません。つまりスペシャルフォームやマクロは、apply
では意味をもちません。
(setq f 'list) ⇒ list
(apply f 'x 'y 'z) error→ Wrong type argument: listp, z
(apply '+ 1 2 '(3 4)) ⇒ 10
(apply '+ '(1 2 3 4)) ⇒ 10
(apply 'append '((a b c) nil (x y z) nil)) ⇒ (a b c x y z)
apply
を使用した興味深い例は、Definition of mapcarを参照してください。
ある関数にたいして、その関数のある引数を特定の値に固定し、他の引数は実際に呼びだされたときの値にできれば便利なことがあります。関数のいくつかの引数を固定することは、その関数の部分適用(partial application)と呼ばれます9。結果は、残りの引数をとる新たな関数で、すべての引数を合わせて元の関数を呼び出します。
Emacs Lispで部分適用を行う方法を示します:
この関数は、新たな関数をreturnします。この新しい関数は、呼びだされたときにargsと、呼び出し時に指定された追加の引数から成る引数リストでfuncを呼び出す関数です。funcにn個の引数を指定できる場合、m < n
個の引数でapply-partially
を呼び出すと、n - m
個の新たな関数を生成します。
以下は、apply-partially
と他のビルトイン関数+
,を使用して、(もし存在しないなら)ビルトイン関数1+
を定義する例です:
(defalias '1+ (apply-partially '+ 1) "Increment argument by one.")
(1+ 10) ⇒ 11
引数として関数をとったり、データ構造(特にフック変数やプロパティーリスト)から関数を探す関数はLispでは一般的で、それらはfuncall
やapply
を使用してそれらの関数を呼び出します。引数として関数をとる関数は、ファンクショナル(functional)と呼ばれるときもあります。
ファンクショナルを呼び出すとき、引数としてno-op関数(何も行わない関数)を指定できると便利なときがあります。以下に2つの異なるno-op関数を示します:
この関数はargをreturnします。副作用はありません。
この関数は任意の引数を無視して、nil
をreturnします。
いくつかの関数はユーザーに可視なコマンドで、これらは(通常はキーシーケンスを介して)対話的に呼び出すことができます。そのようなコマンドは、call-interactively
関数を使用することにより、対話的に呼びだされたときと同様に呼び出すことができます。Interactive Callを参照してください。
これはカリー化(currying)と関連しますが、異なる機能です。カーリングは、複数の引数をとる関数を、関数チェーンとして呼び出せるような、1つの引数を取る個々の関数に変換するような方法です。