= Solution
Use the ordinary fraction identities, returning fresh records rather than changing either argument:
``
PROCEDURE addRat(x,y: rational): rational;
BEGIN
RETURN mkRat(x.num*y.den + y.num*x.den, x.den*y.den)
END addRat;
PROCEDURE mulRat(x,y: rational): rational;
BEGIN
RETURN mkRat(x.num*y.num, x.den*y.den)
END mulRat;
PROCEDURE negRat(x: rational): rational;
BEGIN
RETURN mkRat(-x.num,x.den)
END negRat;
``
Every result is reduced by `mkRat`. This preserves the <representation invariant> even if an input was initially unreduced, provided its denominator is nonzero. <Aliasing> between the arguments causes no problem because their fields are only read.
Back to article page