ヴァリアント

type 宣言を使って宣言できるデータにはヴァリアントというのもある。おおざっぱに言うと「作り方に何種類か方法があるようなデータ」。Haskellでいう代数的データ型と同じと思っていいのかな。
たとえば次のようなものがヴァリアント。

 # type figure = 
     Point
   | Circle of int
   | Rectangle of int * int
   | Square of int
   ;;
 type figure = Point | Circle of int | Rectangle of int * int | Square of int

figure は図形を表すヴァリアントで,Point,Circle,Rectangle,Square をコンストラクタといい,ここではそれぞれ点,円,長方形,正方形を表している。コンストラクタはヴァリアントの値を作るのに使われる。
of に続くのはそれぞれの図形の大きさを表すための型(ここではすべて整数にしてある)。

ヴァリアントの値は,コンストラクタを(関数のように)適用することで作ることができる。

 # let c = Circle 3;;
 val c : figure = Circle 3
 # let r = Rectangle (3,4);;
 val r : figure = Rectangle (3, 4)

ただ,Rectangle のようにタプルをとるように見えるコンストラクタでも,別のところで作ったタプルに適用することはできない。

 # let p = (2, 5);;
 val p : int * int = (2, 5)
 # let r2 = Rectangle p;;
 Characters 9-20:
   let r2 = Rectangle p;;
            ^^^^^^^^^^^
 The constructor Rectangle expects 2 argument(s),
 but is here applied to 1 argument(s)


Point,Circle,Rectangle,Square はどれも figure 型なので,一つにリストに入れることができる。

 # let figs = [Point; c; r; Square 5];;
 val figs : figure list = [Point; Circle 3; Rectangle (3, 4); Square 5]

もちろん関数でもひとまとめに扱える。それぞれのコンストラクタで扱いが違うときには,パターンマッチング(ヴァリアントパターン)を使う。

 # let area_of_figure = function
     Point -> 0
   | Circle r -> r * r * 3
   | Rectangle (x, y) -> x * y
   | Square x -> x * x
   ;;
 val area_of_figure : figure -> int = <fun>
 # area_of_figure c;;
 - : int = 27
 # area_of_figure r;;
 - : int = 12
 # List.map area_of_figure figs;;
 - : int list = [0; 27; 12; 25]