関数の合成

2つの関数を f と g とすれば f . g と単純に行くのは g の引数が1つの場合だけ。2つ以上の引数をとる場合にはちょっと複雑になる。次のような関数で確かめてみる。

 f a = a:[]
 
 g  a     = a:[]
 g2 a b   = a:b:[]
 g3 a b c = a:b:c:[]

まずは簡単な f と g

 *Main> :t f . g
 f . g :: a -> [[a]]

引数を2つとる g2 に対して同じようにやると

 *Main> :t (f . g2)
 (f . g2) :: a -> [a -> [a]]

こんな型になって2つの引数をうまく追い出せない。

 *Main> (f . g2) 1 2
 
 <interactive>:1:0:
     Couldn't match `[a -> [a]]' against `t -> t1'
       Expected type: [a -> [a]]
       Inferred type: t -> t1
     Probable cause: `(f . g2)' is applied to too many arguments in the call
         ((f . g2) 1 2)
     In the definition of `it': it = (f . g2) 1 2

追い出してやるには,関数合成を2段階にする。

 *Main> :t ((f .) . g2)
 ((f .) . g2) :: a -> a -> [[a]]
 *Main> ((f .) . g2) 1 2
 [[1,2]]

引数が3つの場合には3段階。

 *Main> :t (((f .) .) . g3)
 (((f .) .) . g3) :: a -> a -> a -> [[a]]
 *Main> (((f .) .) . g3) 1 2 3
 [[1,2,3]]


逆に1つ目の関数のほうが複数引数の時は単純に合成できる。

 *Main> :t g3 . f
 g3 . f :: a -> [a] -> [a] -> [[a]]

ただし,引数のほうがややこしい。上の例で行くと1つ目の引数は f の引数,2つ目以降が g3 の2番目3番目の引数となる。こうすればわかりやすい。

 g3 (f a) b c

実行。

 *Main> (g3 . f) 1 [2] [3]
 [[1],[2],[3]]


じゃあ,引数が3つと2つならどうだ。

 *Main> :t (g3 .) . g2
 (g3 .) . g2 :: a -> a -> [a] -> [a] -> [[a]]
 *Main> ((g3 .) . g2) 1 2 [3] [4]
 [[1,2],[3],[4]]

ああ,ややこしい。