1.3 値としての関数

Caml は関数型言語です。関数は当然数学的な意味の関数としても使えますし、他のデータと同じように自由に扱うことも出来ます。例として deriv 関数を示します。この関数は浮動小数点関数を引数にとり、導関数の近似を返します。

#let deriv f dx = function x -> (f(x +. dx) -. f(x)) /. dx;;
val deriv : (float -> float) -> float -> float -> float = <fun>

#let sin' = deriv sin 1e-6;;
val sin' : float -> float = <fun>

#sin' pi;;
- : float = -1.00000000014
    

関数の合成も定義出来ます。

#let compose f g = function x -> f(g(x));;
val compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun>

#let cos2 = compose square cos;;
val cos2 : float -> float = <fun>
    

関数の引数として渡された関数は「汎関数」や「高階関数」と呼ばれます。高階関数は特にイテレータのような、データ構造上の汎用の操作を提供するのに有用です。たとえば、標準 Caml ライブラリに List.map という関数がありますが、この関数は引数に与えられた関数を、すべてのリストの要素に適用し、その結果のリストを返します。

#List.map (function n -> n * 2 + 1) [0;1;2;3;4];;
- : int list = [1; 3; 5; 7; 9]
    

List.map や他のリスト、配列関連の高階関数は、使用頻度が高いので、既にライブラリとして定義されていますが、何も特別なことはしていません。 下に示すように簡単に定義することができるのです。

#let rec map f l =
   match l with
     [] -> []
   | hd :: tl -> f hd :: map f tl;;
val map : ('a -> 'b) -> 'a list -> 'b list = <fun>