読者です 読者をやめる 読者になる 読者になる

bitterharvest’s diary

A Bitter Harvestは小説の題名。作者は豪州のPeter Yeldham。苦闘の末に勝ちえた偏見からの解放は命との引換になったという悲しい物語

Haskell入門 型があってのHaskell

1.コンパイルできれば完了

Haskellは静的型付けき言語である。このおかげで、信頼性の高いプログラムを作成できる。CやJavaでプログラムを作成するとデバッグに多くの時間がとられる。Haskellだとそのようなことはない。コンパイル出来た瞬間にプログラムが出来上がっている場合が殆どである。

もう一度、ソートのプログラムに登場してもらう。このプログラムは次のようになっていた。

quicksort [] = []
quicksort (x:xs) = quicksort smaller ++ [x] ++ quicksort larger
  where
    smaller = [a | a <- xs, a <  x]
    larger = [a | a <- xs, a >= x]

このプログラムは、適当な整数のリストを与えたとき昇順に並べてくれた。また、文字のリストを与えたときも、文字列のリストを与えたときもそのようにしてくれた。それでは、整数と文字を混ぜ合わせたリストを与えるとどのようになるか見ることにする。
f:id:bitterharvest:20140924113601p:plain

予想した通り、プログラムは動かない。エラーメッセージは、Num(数字)とChar(文字)を含んだインスタンスが存在しないといっている。さらに、解決する方法は、Num(数字)とChar(文字)を含んだインスタンスを宣言しなさいと言っている。これは、文字と文字列からなるリストを与えたとしても同じである。インスタンスの話をするのは少し後にして、Haskellの型についてしばらく話をする。

Haskellの関数の定義は、型シグネチャを用いて引数や戻り値の型クラスや型を明示的に示すことができる。もし、型シグネチャがない場合には、システムのほうで補間する。quicksortの型シグネチャがどのようになっているかを調べてみる。これには、:tを用いる。
f:id:bitterharvest:20140924114545p:plain

上記の記述で、=>の左側は引数と戻り値で用いる型クラスや型変数を示す。ここでは、型クラスはOrdで型変数はaである。他方、=>の右側は型変数を用いて引数と戻り値の関係を示す。一番右側は戻り値、->の左側にあるのは引数である。quicksortの場合、引数は一つである。引数、戻り値ともカッコ[]がついている。従って、両者とも型変数aの要素で構成されるリストとなる。Ordは順序付けできるものを意味する型クラスである。

Haskellには、紛らわしいのだが、型クラスと型の二つがある。

型クラスは、何らかの振舞いを定義するインタフェースある。オブジェクト指向のクラスと似た面を有している。例えば、ソートのところで出てきた型クラスOrdは順序付けという振舞いを定義したインタフェースある。インタフェースは関数の形で提供され、Ordでは、標準的な大小関係が用意されている。それらは>,<,>=,<=である。
型クラスはインスタンスを有する。型クラスのところでインタフェースとして定められた関数はインスタンスのところで実際に実装される。

Ord以外の型クラスとしては、等値性のためのEq、文字列表現することを許すShow、文字列を受け取ることを許すRead、列挙することを許すEnum、数のNum、実数のFloating、整数のIntegralなどがある。

型にはInt,Integer,Float,Double,Bool,Char,タプルなどがある。型は型クラスのインスタンスとなることができる。実際、Intは、Eq,Ord,Show,Read,Enum,Num,Integralのインスタンスである。

型変数はコンパイル時または実行時にこれらの型にバインドされる。ソートのプログラムでは、型変数はaであった。型クラスのところでOrdとされているので、順序付けされている型であれば、どのような型ともバインドする。Int,Integer,Float,Double,Bool,Charはいずれも順序付けされているので、aはこれらのいずれともバインドすることができる。

従って、Int型のリストが与えられれば、aはInt型となる。また、Char型であれば、aはChar型となる。しかし、型が入り混じったリストの場合には、aをバインドすることができないので、エラーとなる。