高階関数(map)

高階関数とは、関数を引数や戻り値とするような関数のことです。 高階関数を使いこなせるようになれば コードをコンパクトに記述できるようになります。 また、高階関数に渡すためのちょっとした関数を書くのに カリー化や匿名関数はとても便利なので 是非セットで覚えてしまいましょう。 ところで、カリー化のことを考えると2引数以上の関数は ある意味、全て高階関数であるわけですが ここではとりあえず、関数を引数に取るような関数ということで 色々例を挙げてみたいと思います。 まず、最初に覚えてみたい関数にmap関数があります。 map関数は、一引数の関数fとデータの集合を引数にとり、 集合の一つ一つのデータに関数fを適用した結果の集合を返します。 なお、この時、元の集合は変更されずに 新しい集合が作成されてその値が結果として返ります。 具体的な例をあげてみます。
リストに対するmap関数
//高階関数に渡すための関数を定義
> let add1 x = x + 1;;
val add1 : int -> int
//List.mapはリストに対するmap関数
//List[1..10]の要素全てに1を加算した結果を返す関数
> List.map add1 [1..10];;
val it : int list = [2; 3; 4; 5; 6; 7; 8; 9; 10; 11]

//ちょっとした関数:匿名関数の利用
> List.map (fun x -> x+1) [1..10];;
val it : int list = [2; 3; 4; 5; 6; 7; 8; 9; 10; 11]

//ちょっとした関数:カリー化した関数の利用
> List.map ((+)1) [1..10];;
val it : int list = [2; 3; 4; 5; 6; 7; 8; 9; 10; 11]

//List.mapの結果はリストなので、重ねて利用可能([1..10]に対して2*(x+1)を計算))
> List.map (( * )2) (List.map ((+)1) [1..10]);;
val it : int list = [4; 6; 8; 10; 12; 14; 16; 18; 20; 22]

//fの戻り値は、別の型でもOK。タプルのリストを生成
> List.map (fun x -> (x,10-x)) [1..3];;
val it : (int * int) list = [(1, 9); (2, 8); (3, 7)]

//上記をちょっと応用:mapを組み合わせた順列の生成
> let junretu lst = List.map (fun x -> List.map (fun y -> (x,y)) lst) lst;;
val junretu : 'a list -> ('a * 'a) list list
> junretu [1..3];;
val it : (int * int) list list
= [[(1, 1); (1, 2); (1, 3)]; [(2, 1); (2, 2); (2, 3)];
   [(3, 1); (3, 2); (3, 3)]]
//シーケンス式でも同じことができます
> let junretu2 lst =  [for i in lst -> [for j in lst -> (i,j)]];;
val junretu2: lst: seq<'a> -> ('a * 'a) list list

> junretu2 [1..3];;
val it: (int * int) list list =
  [[(1, 1); (1, 2); (1, 3)]; [(2, 1); (2, 2); (2, 3)];
   [(3, 1); (3, 2); (3, 3)]]
リストだけでなく、配列に対するmapやジェネリックなmap関数もあります。
他の型に対するmap関数
//配列に対するmap
> Array.map ((+)1) [|1..10|];;
val it : int [] = [|2; 3; 4; 5; 6; 7; 8; 9; 10; 11|]
//Genericなmap
> Seq.map ((+)1) [1..10];;
val it : seq<int> = seq [2; 3; 4; 5; ...]
> Seq.map ((+)1) [|1..10|];;
val it : seq<int> = seq [2; 3; 4; 5; ...]
もちろん、他にもSetやHash,木構造など、 データの集合であればmap関数を考えることができます。 最後に、リストに対するmap関数の実装例をあげて この節を締めくくります。
リストに対するmap関数の実装
> let rec mymap f lst =
-     match lst with
-     | [] -> []
-     | h::t -> (f h)::mymap f t;;
val mymap : ('a -> 'b) -> 'a list -> 'b list

> mymap ((+)1) [1..10];;
val it : int list = [2; 3; 4; 5; 6; 7; 8; 9; 10; 11]