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がリターンした値をリターンする。
funcall
は関数なので、functionを含むすべての引数はfuncall
の呼び出し前に評価される。これは呼び出される関数を得るために任意の式を使用できることを意味している。またfuncall
がargumentsに記述した式ではなく、その値だけを見ることを意味している。これらの値はfunction呼び出し中では、2回目は評価されない。funcall
の処理は関数の通常の呼び出し手続きと似ており、すでに評価された引数は評価されない。
引数functionはLisp関数かプリミティブ関数でなければならない。つまりスペシャルフォームやマクロは、未評価の引数式を与えられたときだけ意味があるので、指定することはできない。上述したように最初の場所でfuncall
がそれらを知らないので、funcall
がそれらを提供することはできない。
コマンドの呼び出しにfuncall
を使用して、それがインタラクティブに呼び出されたように振る舞うようにする必要があるなら、funcall-interactively
を使用すること(Interactive Callを参照)。
(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を呼び出した結果をリターンする。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)と呼ばれます11。これの結果は残りの引数をとる新たな関数で、すべての引数を合わせて元の関数を呼び出します。
Emacs Lispで部分適用を行う方法を示します:
この関数は新たな関数をリターンする。この新しい関数は呼びだされたときにargs、および呼び出し時に指定された追加の引数から成る引数リストでfuncを呼び出す関数である。funcにn個の引数を指定できる場合、m < n
個の引数でapply-partially
を呼び出すと、n - m
個の新たな関数を生成する。
以下はビルトイン関数1+
が存在しないものとして、apply-partially
と他のビルトイン関数+
を使用して1+
を定義する例である:
(defalias '1+ (apply-partially '+ 1) "Increment argument by one.")
(1+ 10) ⇒ 11
引数として関数を受け取ったり、データ構造(特にフック変数やプロパティーリスト)から関数を探す関数はLispでは一般的で、それらはfuncall
やapply
を使用してそれらの関数を呼び出します。引数として関数をとる関数は、ファンクショナル(functional)と呼ばれるときもあります。
ファンクショナルを呼び出すとき、引数としてno-op関数(何も行わない関数)を指定できると便利なときがあります。以下に2つの異なるno-op関数を示します:
この関数はargumentをリターンする。副作用はない。
この関数はすべてのargumentsを無視してnil
をリターンする。
関数のいくつかはユーザーに可視なコマンドで、これらは(通常はキーシーケンスを介して)対話的に呼び出すことができます。そのようなコマンドは、call-interactively
関数を使用することにより、対話的に呼びだされたときと同様に呼び出すことができます。Interactive Callを参照してください。
これはカリー化(currying)と関連しますが異なる機能です。カーリングは複数の引数を受け取る関数を、関数チェーンとして呼び出せるような1つの引数を取る個々の関数に変換するような方法です。