関数の合成

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]]

ああ,ややこしい。