Next: , Previous: , Up: Functions   [Contents][Index]


12.5 関数の呼び出し

関数を定義しただけでは半分しか終わっていません。関数はそれを呼び出す(call) — たとえば実行(run)するまでは何も行いません。関数のcallはinvocationとしても知られています。

関数を呼び出すもっとも一般的な方法は、リストの評価によるものです。たとえばリスト(concat "a" "b")を評価することにより、関数concatが引数"a""b"で呼び出されます。評価についてはEvaluationを参照してください。

プログラム内で式としてリストを記述するときは、プログラム内にテキストでどの関数を呼び出すか、いくつの引数を与えるかを指定します。通常はこれが行いたいことです。どの関数を呼び出すかを実行時に計算する必要がある場合もあります。これを行うには関数funcallを使用します。実行時にいくつの引数を渡すか決定する必要があるときはapplyを使用します。

Function: funcall function &rest arguments

funcallは関数functionを引数argumentsで呼び出して、functionがリターンした値をリターンする。

funcallは関数なので、functionを含むすべての引数はfuncallの呼び出し前に評価される。これは呼び出される関数を得るために任意の式を使用できることを意味している。またfuncallargumentsに記述した式ではなく、その値だけを見ることを意味している。これらの値は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の例と比較されたい。

Function: apply function &rest arguments

applyは関数functionを引数argumentsで呼び出す。これはfuncallと同様だが1つ違いがある。argumentsの最後はオブジェクトのリストである。これは1つのリストではなく、個別の引数としてfunctionに渡される。わたしたちはこれを、applyがこのリストを展開(spread)(個々の要素が引数となるので)すると言う。

applyfunctionを呼び出した結果をリターンする。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で部分適用を行う方法を示します:

Function: apply-partially func &rest args

この関数は新たな関数をリターンする。この新しい関数は呼びだされたときにargs、および呼び出し時に指定された追加の引数から成る引数リストでfuncを呼び出す関数である。funcn個の引数を指定できる場合、m < n個の引数でapply-partiallyを呼び出すと、n - m個の新たな関数を生成する。

以下はビルトイン関数1+が存在しないものとして、apply-partiallyと他のビルトイン関数+を使用して1+を定義する例である:

(defalias '1+ (apply-partially '+ 1)
  "Increment argument by one.")
(1+ 10)
     ⇒ 11

引数として関数を受け取ったり、データ構造(特にフック変数やプロパティーリスト)から関数を探す関数はLispでは一般的で、それらはfuncallapplyを使用してそれらの関数を呼び出します。引数として関数をとる関数は、ファンクショナル(functional)と呼ばれるときもあります。

ファンクショナルを呼び出すとき、引数としてno-op関数(何も行わない関数)を指定できると便利なときがあります。以下に2つの異なるno-op関数を示します:

Function: identity arg

この関数はargをリターンする。副作用はない。

Function: ignore &rest args

この関数はすべての引数を無視してnilをリターンする。

関数のいくつかはユーザーに可視なコマンドで、これらは(通常はキーシーケンスを介して)対話的に呼び出すことができます。そのようなコマンドは、call-interactively関数を使用することにより、対話的に呼びだされたときと同様に呼び出すことができます。Interactive Callを参照してください。


Footnotes

(9)

これはカリー化(currying)と関連しますが異なる機能です。カーリングは複数の引数を受け取る関数を、関数チェーンとして呼び出せるような1つの引数を取る個々の関数に変換するような方法です。