signature RATIONAL = sig type int type t exception DenominatorIsZero val zero: t val one: t val rat: int * int -> t val fromInt: int -> t val numerator: t -> int val denominator: t -> int val numdenom: t -> int * int val isZero: t -> bool val isNeg: t -> bool val isPos: t -> bool val eq: t * t -> bool val rneg: t -> t val radd: t * t -> t val rsub: t * t -> t val rmul: t * t -> t exception DivisionByZero val rdiv: t * t -> t val initialize: unit -> unit val enumerate: unit -> t val toString: t -> string end functor Rational (Integer:INTEGER):> RATIONAL where type int = Integer.int = struct structure I = Integer type int = I.int type t = int * int open Integer val z = I.fromInt 0 val sz = I.fromInt 1 val zero = (z, sz) val one = (sz, sz) fun gcd (m:int, n:int): int = (* m and n are nonnegative *) if m <= z then n else gcd (n mod m, m) fun numerator ((p, q): t) = p fun denominator ((p, q): t) = q fun numdenom ((p, q): t): int * int = (p, q) fun isZero ((p, q): t): bool = (sign (p) = 0) fun isPos ((p, q): t): bool = Int31.> (sign (p), 0) fun isNeg ((p, q): t): bool = Int31.< (sign (p), 0) fun eq ((p1, q1): t, (p2, q2): t) = (p1 = p2) andalso (q1 = q2) exception DenominatorIsZero fun rat0 (p:int, q:int): t = let val r = if p >= z then gcd (p, q) else gcd (~p, q) in (p div r, q div r) end fun fromInt (n: int): t = (n, sz) fun rat (p:int, q:int): t = if (q > z) then rat0 (p, q) else if (q < z) then rat0 (~p, q) else raise DenominatorIsZero fun rneg ((p, q): t) = (~p, q) fun radd ((p1, q1):t, (p2, q2):t): t = rat0 (p1 * q2 + p2 * q1, q1 * q2) fun rsub ((p1, q1):t, (p2, q2):t): t = rat0 (p1 * q2 - p2 * q1, q1 * q2) fun rmul ((p1, q1):t, (p2, q2):t): t = rat0 (p1 * p2, q1 * q2) exception DivisionByZero fun rdiv ((p1, q1):t, (p2, q2):t): t = if p2 = z then raise DivisionByZero else rat (p1 * q2, p2 * q1) val (num, sum) = (ref z, ref sz) fun initialize () = (num := z; sum := z) fun enumerate (): t = if !num >= !sum then let val thousand = I.fromInt 1000 val _ = num := sz val _ = sum := !sum + sz val _ = if !sum mod thousand <= z then print ("enumerate: sum = " ^ toString (!sum) ^ "\n") else () in enumerate () end else let val p = !num val _ = num := p + sz val q = !sum - p val r = gcd (p, q) in if r > sz then enumerate () else (p, q) end fun toString ((p, q): t): string = if q = sz then I.toString p else I.toString p ^ "/" ^ I.toString q end