主なデータ型
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
型用)と div
(int
型, 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
この例では,ラベルとして name
と age
を持つレコードを作成しています.
ここで作成したレコード 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
すべての等値型には,比較演算子 =
および <>
が使えます.