主なデータ型

1. 主なデータ型とリテラル

ML で利用できる基本データ型には以下のようなものがあります.

説明 リテラルの例

bool

論理型

true, false

int

整数型(符号付き整数型)

123, 0x1a, ~123(負数)

word

ワード型(符号なし整数型)

0w123, 0wx1a

real

実数型

3.14, ~3.14, 1.23e4, 1.23e~4

char

文字型

#"a", #"\n"

string

文字列型

"abc\n"

unit

ユニット型(0-タプル)

()

複合型として,タプル型,レコード型,リスト型があります.

型(例) 説明 リテラルの例

int * int * string

タプル型(値の組)

(123, 456, "abc")

{ a : int, b : int, c : string }

レコード型(ラベル付き値の集合)

{ a = 123, b = 456, c = "abc" }

int list

リスト型(値の列)

[3, 1, 4, 2, 5]

2. 論理型

論理型の定数は true と false です. 演算には not(否定), andalso(論理積), orelse(論理和)が使えます. and, or でなく andalso, orelse なのが奇妙ですが,これは and が別の用途に予約されているためです.

- not true;
val it = false : bool

- it orelse true;
val it = true : bool

3. 数値型

数値型の演算には ~(単項マイナス), +(加算), -(減算), *(乗算), abs(絶対値)などが使えます. 除算演算子には,/real 型用)と divint型, word型用)の2種類があります. 剰余演算子は mod で,int型とword型で利用できます.

- 2 * 3;
val it = 6 : int
- ~ it;
val it = ~6 : int
- abs it;
val it = 6 : int

- 10.0 / 3.0;
val it = 3.33333333333 : real
- 10 div 3;
val it = 3 : int
- 10 mod 3;
val it = 1 : int

これらの算術演算子は,2引数が同一の型でなければ利用できません. 例えば 2 + 3.0 は型エラーになります. real(2) + 3.0 のように,適切に型を揃える必要があります.

- 2 + 3.0;
stdIn:34.1-34.8 Error: operator and operand don't agree [literal]
  operator domain: int * int
  operand:         int * real
  in expression:
    2 + 3.0

- real(2) + 3.0;
val it = 5.0 : real
整数型から実数型への変換には real 関数が利用できます. 実数型から整数型への変換には,ceil(∞方向丸め), floor(-∞方向丸め), trunc(0 方向丸め), round(四捨五入)といった関数が利用できます.

関係演算子には,>, >=, <, <=, =, <> があります. (real 型の値には ==<> は使えません.)

- 2 > 3;
val it = false : bool

- 2 <> 3;
val it = true : bool

4. 文字型/文字列型

詳細は割愛しますが,文字にも文字列にも,\n のようなエスケープシーケンスが利用できます. また,文字列の連結には ^ 演算子を使います.

- "hello\n";
val it = "hello\n" : string

- "abc" ^ "def";
val it = "abcdef" : string

5. タプル型/ユニット型

タプル(tuple)は複数の値を組にしたものです. 例えば,整数 123 と文字列 "abc" のタプルは (123, "abc") のように書き,その型は int * string と書きます.

- (123, "abc");
val it = (123,"abc") : int * string

タプルの n (≥ 1) 番目の要素を取り出すには #n という関数を利用します.

- val t = (123, (456, "abc"));
val t = (123,(456,"abc")) : int * (int * string)

- #1 (#2 t);
val it = 456 : int

ユニット (unit) は要素数 0 のタプルです. ユニット型の唯一の値は () であり,型名は unit です.

ユニット型は,例えば,意味のある値を返さない関数の返却型として使われたりします. 文字列を印字する print 関数の返却型はユニット型です.

6. レコード型

レコード(record)はラベル付き値の集合です.

- val taro = { name = "Taro", age = 25 };
val taro = {age=25,name="Taro"} : {age:int, name:string}

- #age taro;
val it = 25 : int

この例では,ラベルとして nameage を持つレコードを作成しています. ここで作成したレコード taro の型は { age : int, name : string } です. レコードの各要素を取り出すには,#name#age のような名前の関数(セレクタ関数)を使います.

7. リスト型

リスト(list)は要素を一列に連結して作られるデータ構造です. 整数のリストは [1, 2, 3] のように書き,型は int list と書きます. 要素数 0 のリスト (空リスト) は [] または nil と書きます.

- [1, 2, 3];
val it = [1,2,3] : int list

- nil;
val it = [] : 'a list

- [];
val it = [] : 'a list

リストについての詳細は "リスト" のページで扱います.

8. 多相型

以下のプログラムは,恒等関数(引数の値をそのまま返す関数)を定義したものです.

- fun id x = x;
val id = fn : 'a -> 'a

- id 5;
val it = 5 : int

この id 関数の型が 'a -> 'a と推論されていることがわかります. 'a のようにアポストロフィで始まるパラメータは型変数(type variable)と呼ばれ,任意の型を表します. 'a -> 'a は,id 関数が,例えば int -> int としても振る舞うし,char -> char 型としても振る舞うことを意味しています.

9. 等値型

1 個のアポストロフィで始まる型変数は任意の型を表しますが,2 個以上のアポストロフィで始まる型変数(''a など)は等値型のみを表します. 等値型(equality type)とは,関数 = で等値比較可能な型のことです.bool, int, char, string などの離散的なデータ型は等値型であり,等値型から構成されるタプルやリストなどの複合型も等値型です. ただし,real 型や関数の型などは等値型ではありません.

次のように,id 関数の引数の型を ''a と指定すると,非等値型には関数を適用できなくなることが分かります.

- fun id (x : ''a) = x
val id = fn : ''a -> ''a

- id 3.14;
stdIn:64.1-64.8 Error: operator and operand don't agree [equality type required]
  operator domain: ''Z
  operand:         real
  in expression:
    id 3.14

すべての等値型には,比較演算子 = および <> が使えます.