関数の型

連休前は仕事がつまってこのblogの更新もままならないほどのGW進行だったというのに,いざ休みになってみると一転,だらけモードで逆の意味でGW進行になってしまった。なんてこった。
気を取り直していこう。まずはこの間(id:takatoh:20060429:tr)はまった関数の型から。

Haskell の関数には型がある。簡単に言うとどんな型の引数をとってどんな型の値を返すか,というのが関数の型。
GHCi では :type コマンドで確認できる。たとえば length は何かのリストを引数にとってその長さ(Int型)を返す。

Prelude> :type length
length :: [a] -> Int

この表記を型式(かたしき)という。
[a] は「何かのリスト」を表していて,その「何か」はChar でも Int でもそのほかの何でもいい。とにかくリストならいいわけだ。
これを多相型(polymorphic type)といい,表記に使われている a を型変数(type variable)という。

Prelude> :type zip
zip :: [a] -> [b] -> [(a, b)]

型変数に a と b が使われているのは,一般に違う型であることを表している。おなじ型でもかまわない。
関数を引数にとる高階関数はこんな風に表される。

Prelude> :type map
map :: (a -> b) -> [a] -> [b]

(a -> b) が引数の関数を表している。

さて,ここからがこの間のキモに関わる部分。型式のなかに -> という記号が使われているが,これは

  • 型に関する二項演算子で
  • 右結合

だ。つまり,map は

map :: (a -> b) -> ([a] -> [b])

とも解釈できる。この意味するところは,「(a -> b) である関数を一つ引数にとって,([a] -> [b])である関数を返す」関数だということ。実際にやってみると

Prelude> :type map (\x -> x * 2)
map (\x -> x * 2) :: (Num a) => [a] -> [a]

引数にした関数の都合で両方とも a になってしまったが,ちゃんと「リスト([a])を引数にとってリスト([a])を返す」関数になっている。

それと, (Num a) => の部分も引数にした関数の都合で現れたものだけど,これは別のエントリで改めて書くことにしよう。
今日はこれくらいで。