(* Third version of Rational that uses a signature to restrict what parts of the structure are exposed, hiding private functions like gcd and reduce_rational. *) module type RATIONAL = sig type rational = Whole of int | Fraction of int * int exception Not_a_rational val make_fraction : int * int -> rational val add : rational * rational -> rational val to_string : rational -> string end module Rational : RATIONAL = struct type rational = Whole of int | Fraction of int * int exception Not_a_rational let rec gcd(x, y) = if x < 0 || y < 0 then gcd(abs(x), abs(y)) else if y = 0 then x else gcd(y, x mod y) let rec reduce_rational(r) = match r with | Whole(i) -> Whole(i) | Fraction(a, b) -> if b < 0 then reduce_rational(Fraction(-a, -b)) else let d = gcd(a, b) in if b = d then Whole(a/d) else Fraction(a/d, b/d) (* client: please always construct fractions with this function *) let make_fraction(a, b) = if b = 0 then raise Not_a_rational else reduce_rational(Fraction(a, b)) let add(r1, r2) = match (r1, r2) with | (Whole i, Whole j) -> Whole(i + j) | (Whole i, Fraction(j, k)) -> Fraction(j + k * i, k) | (Fraction(j, k), Whole i) -> Fraction(j + k * i, k) | (Fraction(a, b), Fraction(c, d)) -> reduce_rational(Fraction(a * d + c * b, b * d)) let to_string(r) = match r with | Whole i -> string_of_int(i) | Fraction(a, b) -> string_of_int(a) ^ "/" ^ string_of_int(b) end