連休前は仕事がつまってこの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) => の部分も引数にした関数の都合で現れたものだけど,これは別のエントリで改めて書くことにしよう。
今日はこれくらいで。