型
値をその種類に応じて分類したものを型とよびます。例えば整数値は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型の値の最小公倍数を求める関数を定義してください。