(* CSE 341, Marty Stepp A structure represents a reusable module of ML code. This structure contains a data type to represent rational numbers (fractions) and associated functions to process them. Today's version uses a signature called RATIONAL so that it cannot be misused by clients. Example usage: val r1 = Rational.new(~2, ~3); (* 2/3 *) val r2 = Rational.new(2, ~12); (* -1/6 *) val r3 = Rational.add(r1, r2); (* 1/2 *) *) use "RATIONAL.sml"; structure Rational :> RATIONAL = struct datatype rational = Whole of int | Fraction of int * int; exception TheRoof; fun compare(Whole(a), Whole(b)) = Int.compare(a, b) | compare(Fraction(a, b), Whole(c)) = Int.compare(a, c*b) | compare(Whole(c), Fraction(a, b)) = Int.compare(a, c*b) | compare(Fraction(a, b), Fraction(c, d)) = Int.compare(a*d, c*b); (* Produces the greatest common divisor (largest common factor) of a and b. *) fun gcd(a, 0) = abs(a) | gcd(a, b) = gcd(b, a mod b); (* Converts a rational number into reduced form, e.g. turns 4/12 into 1/3. *) fun reduce(Whole(a)) = Whole(a) | reduce(Fraction(a, b)) = let val g = gcd(a, b) val n = a div g val d = b div g in if g = abs(b) then Whole(a div b) else if b < 0 then Fraction(~n, ~d) else Fraction(n, d) end; fun new(a, 0) = raise TheRoof | new(a, b) = reduce(Fraction(a, b)); (* Adds the two given rational numbers and produces the result. The result is given in 'reduced' form (e.g. 1/3 not 4/12). *) fun add(Whole(a), Whole(b)) = Whole(a+b) | add(Whole(a), Fraction(b, c)) = Fraction(a*c+b, c) | add(Fraction(b, c), Whole(a)) = Fraction(a*c+b, c) | add(Fraction(a, b), Fraction(c, d)) = reduce(Fraction(a*d+b*c, b*d)); (* Converts a rational number into a string such as "1/3". *) fun toString(Whole(a)) = Int.toString(a) | toString(Fraction(a, b)) = Int.toString(a) ^ "/" ^ Int.toString(b); end;