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


13.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がそれらを知らないので、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の例と比較されたい。

Function: apply function &rest arguments

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

単一の引数でのapplyは特別である。引数(非空のリスト)の最初の要素は、残りの要素を個別の引数に関数として呼び出される。2つ以上の引数を渡すほうが早くなるだろう。

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 '(+ 3 4))
     ⇒ 7

applyを使用した興味深い例はDefinition of mapcarを参照のこと。

ある関数にたいして、その関数のある引数を特定の値に固定して、他の引数は実際に呼びだされたときの値にできれば便利なことがあります。関数のいくつかの引数を固定することは、その関数の部分適用(partial application)と呼ばれます11。これの結果は残りの引数をとる新たな関数で、すべての引数を合わせて元の関数を呼び出します。

Emacs Lispで部分適用を行う方法を示します:

Function: apply-partially func &rest args

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

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

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

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

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

Function: identity argument

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

Function: ignore &rest arguments

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

Function: always &rest arguments

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

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


Footnotes

(11)

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

(12)

funcが受け取ることができる引数の個数に制限がない場合には、新たな関数が受け取ることができる引数の個数も無制限になるので、このようなケースではapply-partiallyは新たな関数が受け取ることができる引数の個数を減らしません。

(13)

ビルトイン関数とは異なり、このバージョンでは任意個数の引数を許容することに注意してください。