型
値をその種類に応じて分類したものを型とよびます。例えば整数値はInt
型に所属しています。Mokkosuではlet
文で値に名前を付けると出力ウインドウに型が表示されます。
以下のプログラムをコンパイルしてみます。
let n = 42;
let t = (2, 3);
fun f = { x -> x * 2 };
fun g = { (x, y) -> x + y };
出力ウインドウには以下のように表示されます。
n : Int
t : (Int, Int)
f : Int -> Int
g : (Int, Int) -> Int
42
は整数値なので、型にはInt
と表示されます。タプルの型は、要素の型を括弧で囲んで並べたものになります。上の例では整数の2要素タプルなので、型は(Int, Int)
になります。関数の型は引数の型をα
戻り値の型をβ
とすると、α -> β
と表します。上の関数f
は整数を受け取って整数を返すのでInt -> Int
型になります。関数g
は引数が正巣のタプル、戻り値は整数なので、(Int, Int) -> Int
になります。
ユーザ定義型
型はユーザが定義することもできます。例えば、Red
、Blue
、Green
の3つの値から構成される型Color
は以下のように定義できます。
type Color = Red | Blue | Green;
このように定義しておくと、Red
、Blue
、Green
は値としてプログラム中で自由に使えます。以下はColor
型の値を使って、Red
を0
、Blue
を1
、Green
を2
に対応付ける関数の定義例です。
fun color_to_int = { ~Red -> 0; ~Blue -> 1; ~Green -> 2 };
プログラム中の~
は、指定した名前が変数名ではなくタグの名前であることを示しています。コンパイルするとcolor_to_int
の型は以下のようになります。
color_to_int : Color -> Int
自分で定義した型と値が組み込みの型(例えばInt
型)と同じように扱えていることが分かると思います。
ユーザ定義型の値には引数を持たせることができます。例えば以下のMaybeInt
のような型を定義できます。
type MaybeInt = Success(Int) | Failure;
この型を使うと例えば以下のような関数を定義できます。
fun div = { (_, 0) ? -> Failure; (x, y) -> Success(x / y) };
関数div
は割り算をする関数です。ただし0
で除算しようとするとFailure
という値を返し、割り算に成功した場合はSuccess(Int)
という値を返します。
自然数の定義
ユーザ定義型を使う練習の一環として、ユーザ定義型で自然数を定義してみましょう。自然数は以下のように定義することができます。
type Nat = Zero | Succ(Nat);
このように、定義の中で自分自身の型を使うことができます。この定義を使うと例えば自然数の3
は、
let three = Succ (Succ (Succ (Zero)));
のように表すことができます。
さて、Nat
に関する関数をいろいろと定義していきましょう。
まずは、Nat
型の値をInt
型の値に変換する関数nat_to_int
です。
fun nat_to_int = {
~Zero -> 0;
~Succ(n) -> 1 + nat_to_int n
};
次は、Nat
同士の足し算です。
fun nat_add = {
(n, ~Zero) -> n;
(n, ~Succ(m)) -> Succ (nat_add (n, m))
};
nat_to_int
とnat_add
関数を使うと、以下のようなプログラムが記述できます。
let two = Succ (Succ (Zero));
let three = Succ (Succ (Succ (Zero)));
let five = nat_add (two, three);
println (nat_to_int five);
練習問題
問題1
Int
型の値をNat
型の値に変換する関数を定義してください。
問題2
Nat
型同士の掛け算を定義してください。
問題3
Nat
型の累乗を定義してください。
問題4
Nat
型の階乗を求める関数を定義してください。
問題5
Nat
型の引き算を定義してください。
問題6
2つのNat
型を割ってその商を求める関数を定義してください。
問題7
2つのNat
型を割ってその余りを求める関数を定義してください。
問題8
2つのNat
型の値を受け取って値が大きい方を返す関数を定義してください。
問題9
2つのNat
型の値を受け取って値が小さい方を返す関数を定義してください。
問題10
2つのNat
型の値の最小公倍数を求める関数を定義してください。