データ型の定義
1. datatype 宣言
次のプログラムは,長方形の大きさを表すデータ型 rectangle
と,長方形の面積を求める関数 area
を宣言したものです.
- datatype rectangle = RECT of real * real;
datatype rectangle = RECT of real * real
- fun area (RECT (w, h)) = w * h;
val area = fn : rectangle -> real
- val r = RECT (3.0, 4.0);
val r = RECT (3.0,4.0) : rectangle
- area r;
val it = 12.0 : real
キーワード datatype
で始まる宣言により,新しいユーザ定義型を定義できます.
datatype
宣言で定義されるデータ型は,代数的データ型(algebraic data type)と呼ばれます.
この例で定義されている rectangle
は型構成子(type constructor),RECT
は値構成子(value constructor)と呼ばれます.
型構成子と値構成子には,同じ名前を用いることもできます.
一つの型に複数の値構成子を定義することもできます.
次のプログラムは,円または長方形を表すデータ型 shape
を定義したものです.
- datatype shape = CIRC of real
| RECT of real * real;
datatype shape = CIRC of real | RECT of real * real
- fun area (CIRC r) = 3.14 * r * r
| area (RECT (w, h)) = w * h;
val area = fn : shape -> real
- val c = CIRC 2.0;
val c = CIRC 2.0 : shape
- area c;
val it = 12.56 : real
次のプログラムは,曜日を表すデータ型 dayofweek
を宣言したものです.
このように,引数のない値構成子のみからなるデータ型は,特に列挙型(enumerated type)と呼ばれます.
- datatype dayofweek = SUM | MON | TUE | WED | THU | FRI | SAT;
datatype dayofweek = FRI | MON | SAT | SUN | THU | TUE | WED
- fun is_holiday SAT = true
| is_holiday SUN = true
| is_holiday _ = false;
val is_holiday = fn : dayofweek -> bool
- is_holiday MON;
val it = false : bool
次のプログラムは,リスト型を模した型を宣言したものです. このように,型引数を導入して多相型を構成することもできます.
- datatype 'a list' = NIL | CONS of 'a * 'a list';
datatype 'a list' = CONS of 'a * 'a list' | NIL
- fun length' NIL = 0
| length' (CONS (x, xs)) = 1 + length' xs;
val length' = fn : 'a list' -> int
- length' (CONS(1, CONS(2, CONS(3, NIL)))); (* length [1,2,3] 相当 *)
val it = 3 : int
2. 型シノニム
存在するデータ型に別名を与えるには,以下のように type
宣言を使います
- type 'a collection = 'a list;
type 'a collection = 'a list
3. 抽象データ型
ここでの抽象データ型(abstract data type)とは,値構成子が隠蔽された型(実装が隠蔽された型)のことをいいます. 抽象データ型を使うことにより,データの実装を隠蔽しつつ,データへのアクセス手段のみをユーザに提供することができます.
次のプログラムは,スタックを表すデータ型 'a stack
と,スタックを操作する関数群を宣言したものです.
このプログラムでは,'a stack
を抽象データ型として宣言しています.
(* file: stack1.sml *)
abstype 'a stack = NIL | INS of 'a * 'a stack
with
(* 新規スタック *)
val new = NIL
(* 要素を先頭に追加する *)
fun push (x, st) = INS (x, st)
(* 先頭要素を取り出す *)
fun pop (INS (x, st)) = (x, st)
end
抽象データ型はキーワード abstype
で始まる宣言により記述します.
with
から end
までの間には,抽象データ型のデータへのアクセス手段となる関数の宣言を記述します.
このプログラムを対話環境で読み込んで,少し遊んでみましょう.
- use "stack1.sml";
[opening stack1.sml]
type 'a stack
val new = - : 'a stack
val push = fn : 'a * 'a stack -> 'a stack
val pop = fn : 'a stack -> 'a * 'a stack
val it = () : unit
- val st = new;
val st = - : 'a stack
- val st = push ("a", st);
val st = - : string stack
- val st = push ("b", st);
val st = - : string stack
- val (x, st) = pop st;
val x = "b" : string
val st = - : string stack
- val (x, st) = pop st;
val x = "a" : string
val st = - : string stack
実行結果が val st = - : string stack
と表示されていることからわかるように,スタックのデータの実装がユーザ側から見えないようになっていることがわかります.
4. 標準のデータ型
標準で定義されている bool
や int
などのデータ型も,datatype
宣言で宣言された代数的データ型とみなすことができます.
例えば,bool
型は次のように宣言されているものと見ることができます.
datatype bool = true | false
int
型も次のように宣言されているものとみなすことができます(実際にすべての整数を列挙することはできませんが…).
datatype int = ... | -2 | -1 | 0 | 1 | 2 | ...
標準で定義されているデータ型のうち未紹介のものに,順序型とオプション型があります.
順序型 order
は次のように宣言されたデータ型で,順序を表すのに使います.
datatype order = LESS | EQUAL | GREATER
オプション型 'a option
は次のように宣言されたデータ型で,値が存在するかしないか不明な文脈で使われます.
(Haskell の Maybe
型,C# のヌル許容型などがこれに相当します.)
datatype 'a option = NONE | SOME of 'a
次のプログラムは,リストの n (≥ 0) 番目の値をオプション型で返す関数 nth
を定義したものです.
オプション型は,このように計算結果が存在するか分からない関数の返却型としてよく使われます.
- fun nth (nil, _) = NONE
| nth (x::xs, 0) = SOME x
| nth (x::xs, n) = nth (xs, n - 1);
val nth = fn : 'a list * int -> 'a option
- nth (["a", "b", "c"], 1);
val it = SOME "b" : string option
- nth (["a", "b", "c"], 5);
val it = NONE : string option