5 | import Data.IntegralGCD
15 | record Ratio a where
25 | Rational = Ratio Integer
31 | numer : Ratio a -> a
36 | (.numer) : Ratio a -> a
42 | denom : Ratio a -> a
48 | (.denom) : Ratio a -> a
56 | reduce : IntegralGCD a => Ratio a -> Ratio a
57 | reduce (MkRatio n d) =
58 | let g = gcd n d in MkRatio (n `div` g) (d `div` g)
63 | mkRatioMaybe : IntegralGCD a => (n, d : a) -> Maybe (Ratio a)
64 | mkRatioMaybe n d = toMaybe (d /= 0) (reduce $
MkRatio n d)
68 | mkRatio : IntegralGCD a => (n, d : a) -> Ratio a
69 | mkRatio n d = case d /= 0 of
70 | True => reduce $
MkRatio n d
77 | unsafeMkRatio : (n, d : a) -> Ratio a
78 | unsafeMkRatio = MkRatio
84 | (//) : IntegralGCD a => (n, d : a) -> {auto 0 ok : So (d /= 0)} -> Ratio a
85 | (//) n d = reduce $
MkRatio n d
90 | floor : Integral a => Ratio a -> a
91 | floor (MkRatio n d) = n `div` d
95 | Eq a => Eq (Ratio a) where
96 | MkRatio n d == MkRatio m b = n == m && d == b
99 | (Ord a, Num a) => Ord (Ratio a) where
100 | compare (MkRatio n d) (MkRatio m b) =
101 | flipIf (b >= 0 `xor` d >= 0) $
compare (n*b) (m*d)
103 | flipIf : Bool -> Ordering -> Ordering
105 | flipIf b LT = if b then GT else LT
106 | flipIf b GT = if b then LT else GT
109 | Show a => Show (Ratio a) where
110 | showPrec p (MkRatio n d) =
112 | in showParens (p >= p') (showPrec p' n ++ " // " ++ showPrec p' d)
115 | IntegralGCD a => Num (Ratio a) where
116 | MkRatio n d + MkRatio m b = reduce $
MkRatio (n*b + m*d) (d*b)
117 | MkRatio n d * MkRatio m b = reduce $
MkRatio (n*m) (d*b)
118 | fromInteger x = MkRatio (fromInteger x) 1
121 | (IntegralGCD a, Neg a) => Neg (Ratio a) where
122 | negate (MkRatio n d) = MkRatio (-n) d
123 | MkRatio n d - MkRatio m b = reduce $
MkRatio (n*b - m*d) (d*b)
126 | (IntegralGCD a, Abs a) => Abs (Ratio a) where
127 | abs (MkRatio n d) = MkRatio (abs n) (abs d)
130 | IntegralGCD a => Fractional (Ratio a) where
131 | recip (MkRatio n d) = case n /= 0 of True => MkRatio d n
132 | MkRatio n d / MkRatio m b = case m /= 0 of
133 | True => reduce $
MkRatio (n*b) (m*d)
138 | Num a => Cast a (Ratio a) where
139 | cast x = MkRatio x 1
142 | Cast a b => Cast (Ratio a) (Ratio b) where
143 | cast (MkRatio n d) = MkRatio (cast n) (cast d)
147 | (Cast a b, Fractional b) => Cast (Ratio a) b where
148 | cast (MkRatio n d) = cast n / cast d