例: 有理数パッケージ

有理数を整数の組で表現してみましょう。 もし有理数の値を表現するためにボックス化された抽象型 rat を宣言したら、 rat 型のそれぞれの値はヒープメモリに保存されます。 そのメモリはガベージコレクション (GC) によってのみ回収できます。 代わりに、 rat をアンボックス化された抽象型として宣言する別のアプローチを取ります。 そこで、次のような宣言になります:

abst@ype rat

この宣言の問題はあまりにも抽象的すぎることです。 rat 型のサイズについて何の情報もないので、 ATSコンパイラは rat 型の値を保存するのに必要なメモリサイズを知ることさえできません。 けれども、プログラマにとってこのような宣言が役に立たないというわけではありません。 実際にはこのような宣言が非常に重要になってくる場面があります。 このトピックは別の章で解説しようと思います。 ここでは、アンボックス化された抽象型を次のように宣言してみましょう:

abst@ype rat = (int, int)

この宣言は、rat 型の値の表現は (int, int) 型の値の表現と同じであることを、単純に ATS コンパイラに伝えています。 けれども、この情報は ATS の型検査器にとって有効ではありません。 とりわけ、プログラム中で rat 型の値が整数のペアとして扱われると、型エラーを引き起こします。

オンライン から取得できる次のコードは ratmod.sats という名前のファイルに保存されています。

exception Denominator exception DivisionByZero fun rat_make_int_int (p: int, q: int): rat fun ratneg: (rat) -> rat // negation fun ratadd: (rat, rat) -> rat // addition fun ratsub: (rat, rat) -> rat // subtraction fun ratmul: (rat, rat) -> rat // multiplication fun ratdiv: (rat, rat) -> rat // division

Denominator 例外は分母がゼロの有理数を誤って生成してしまったことを示します。 有理数の分子と分母を表わす2つの整数が与えられた時、 関数 rat_make_int_int は有理数を表わす値を返します。 rat_make_int_int の次の実装は ratmod.dats という名前のファイルにあり、 オンライン からも取得できます。

implement rat_make_int_int (p, q) = let fun make ( p: int, q: int ) : rat = let val r = gcd (p, q) in (p / r, q / r) end // end of [make] // val () = if q = 0 then $raise Denominator // in if q > 0 then make (p, q) else make (~p, ~q) end // end of [rat_make_int_int]

整数 p とゼロでない整数 q の組が与えられた時、 関数 rat_make_int_int は別の整数の組 p1 と q1 を返します。 ここで、q 1 は正の数で、p1 と q1 は互いに素です。 つまり、それらの最大公約数は1で、p1/q1 は p/q に等しくなります。 rat_make_int_int を使うと、有理数の算術演算は次のように素直に実装できます:

implement ratneg (x) = (~x.0, x.1) implement ratadd (x, y) = rat_make_int_int (x.0 * y.1 + x.1 * y.0, x.1 * y.1) // end of [ratadd] implement ratsub (x, y) = rat_make_int_int (x.0 * y.1 - x.1 * y.0, x.1 * y.1) // end of [ratsub] implement ratmul (x, y) = rat_make_int_int (x.0 * y.0, x.1 * y.1) implement ratdiv (x, y) = ( if y.0 > 0 then rat_make_int_int (x.0 * y.1, x.1 * y.0) else $raise DivisionByZero() // end of [if] ) (* end of [ratdiv] *)

ratmod.sats で宣言されている関数に対するいくらかのテストコードが オンライン から入手できます。