Add explicit `{-# LANGUAGE CPP, PackageImports #-}` pragmas
[packages/haskell2010.git] / Data / Ratio.hs
1 {-# LANGUAGE CPP, PackageImports #-}
2 #if __GLASGOW_HASKELL__ >= 701
3 {-# LANGUAGE Safe #-}
4 #endif
5
6 module Data.Ratio (
7 Ratio
8 , Rational
9 , (%) -- :: (Integral a) => a -> a -> Ratio a
10 , numerator -- :: (Integral a) => Ratio a -> a
11 , denominator -- :: (Integral a) => Ratio a -> a
12 , approxRational -- :: (RealFrac a) => a -> a -> Rational
13
14 -- * Specification
15
16 -- $code
17 ) where
18 import "base" Data.Ratio
19
20 {- $code
21 > module Data.Ratio (
22 > Ratio, Rational, (%), numerator, denominator, approxRational ) where
23 >
24 > infixl 7 %
25 >
26 > ratPrec = 7 :: Int
27 >
28 > data (Integral a) => Ratio a = !a :% !a deriving (Eq)
29 > type Rational = Ratio Integer
30 >
31 > (%) :: (Integral a) => a -> a -> Ratio a
32 > numerator, denominator :: (Integral a) => Ratio a -> a
33 > approxRational :: (RealFrac a) => a -> a -> Rational
34 >
35 >
36 > -- "reduce" is a subsidiary function used only in this module.
37 > -- It normalises a ratio by dividing both numerator
38 > -- and denominator by their greatest common divisor.
39 > --
40 > -- E.g., 12 `reduce` 8 == 3 :% 2
41 > -- 12 `reduce` (-8) == 3 :% (-2)
42 >
43 > reduce _ 0 = error "Data.Ratio.% : zero denominator"
44 > reduce x y = (x `quot` d) :% (y `quot` d)
45 > where d = gcd x y
46 >
47 > x % y = reduce (x * signum y) (abs y)
48 >
49 > numerator (x :% _) = x
50 >
51 > denominator (_ :% y) = y
52 >
53 >
54 > instance (Integral a) => Ord (Ratio a) where
55 > (x:%y) <= (x':%y') = x * y' <= x' * y
56 > (x:%y) < (x':%y') = x * y' < x' * y
57 >
58 > instance (Integral a) => Num (Ratio a) where
59 > (x:%y) + (x':%y') = reduce (x*y' + x'*y) (y*y')
60 > (x:%y) * (x':%y') = reduce (x * x') (y * y')
61 > negate (x:%y) = (-x) :% y
62 > abs (x:%y) = abs x :% y
63 > signum (x:%y) = signum x :% 1
64 > fromInteger x = fromInteger x :% 1
65 >
66 > instance (Integral a) => Real (Ratio a) where
67 > toRational (x:%y) = toInteger x :% toInteger y
68 >
69 > instance (Integral a) => Fractional (Ratio a) where
70 > (x:%y) / (x':%y') = (x*y') % (y*x')
71 > recip (x:%y) = y % x
72 > fromRational (x:%y) = fromInteger x :% fromInteger y
73 >
74 > instance (Integral a) => RealFrac (Ratio a) where
75 > properFraction (x:%y) = (fromIntegral q, r:%y)
76 > where (q,r) = quotRem x y
77 >
78 > instance (Integral a) => Enum (Ratio a) where
79 > succ x = x+1
80 > pred x = x-1
81 > toEnum = fromIntegral
82 > fromEnum = fromInteger . truncate -- May overflow
83 > enumFrom = numericEnumFrom -- These numericEnumXXX functions
84 > enumFromThen = numericEnumFromThen -- are as defined in Prelude.hs
85 > enumFromTo = numericEnumFromTo -- but not exported from it!
86 > enumFromThenTo = numericEnumFromThenTo
87 >
88 > instance (Read a, Integral a) => Read (Ratio a) where
89 > readsPrec p = readParen (p > ratPrec)
90 > (\r -> [(x%y,u) | (x,s) <- readsPrec (ratPrec+1) r,
91 > ("%",t) <- lex s,
92 > (y,u) <- readsPrec (ratPrec+1) t ])
93 >
94 > instance (Integral a) => Show (Ratio a) where
95 > showsPrec p (x:%y) = showParen (p > ratPrec)
96 > showsPrec (ratPrec+1) x .
97 > showString " % " .
98 > showsPrec (ratPrec+1) y)
99 >
100 >
101 >
102 > approxRational x eps = simplest (x-eps) (x+eps)
103 > where simplest x y | y < x = simplest y x
104 > | x == y = xr
105 > | x > 0 = simplest' n d n' d'
106 > | y < 0 = - simplest' (-n') d' (-n) d
107 > | otherwise = 0 :% 1
108 > where xr@(n:%d) = toRational x
109 > (n':%d') = toRational y
110 >
111 > simplest' n d n' d' -- assumes 0 < n%d < n'%d'
112 > | r == 0 = q :% 1
113 > | q /= q' = (q+1) :% 1
114 > | otherwise = (q*n''+d'') :% n''
115 > where (q,r) = quotRem n d
116 > (q',r') = quotRem n' d'
117 > (n'':%d'') = simplest' d' r' d r
118 -}