module Rational2
  ( Rat, normRat, negRat, addRat, mulRat, divRat, showRat,
    compareRat, eqRat, neqRat, ltRat, leqRat, gtRat, geqRat )
where

{- Rational definitions from 5.6 -}

    type Rat = (Int,Int)

    normRat :: Rat -> Rat 
    normRat (x,0) = error ( "Invalid rational number (in normRat) " 
                         ++ showRat (x,0) ++ "\n" ) 
    normRat (0,y) = (0,1) 
    normRat (x,y) = (a `div` d, b `div` d) 
                    where a = (signum' y) * x 
                          b = abs y 
                          d = gcd' a b 

    signum' :: (Num a, Ord a) => a -> Int
    signum' n | n == 0 =  0 
              | n > 0  =  1 
              | n < 0  = -1

    gcd' :: Int -> Int -> Int 
    gcd' x y = gcd'' (abs x) (abs y) 
             where gcd'' x 0 = x 
                   gcd'' x y = gcd'' y (x `rem` y)

    negRat :: Rat -> Rat 
    negRat (a,b) = normRat (-a,b) 

    addRat, subRat, mulRat, divRat :: Rat -> Rat -> Rat 
    addRat (a,b) (c,d) = normRat (a*d + c*b, b*d) 
    subRat (a,b) (c,d) = normRat (a*d - c*b, b*d) 
    mulRat (a,b) (c,d) = normRat (a*c, b*d)
    divRat (a,b) (c,d) = normRat (a*d, b*c) 

-- REDEFINED
--   eqRat :: Rat -> Rat -> Bool 
--   eqRat (a,0) (c,d) = errRat (a,0)
--   eqRat (a,b) (c,0) = errRat (c,0) 
--   eqRat (a,b) (c,d) = (a*d == b*c)        

    errRat (x,y) = error ( "Invalid rational number" 
                           ++ showRat (x,y) )
    showRat :: Rat -> String
    showRat (a,b) = show a ++ "/" ++ show b

-- NOT REALLY PART OF PACKAGE
--   youDirtyRat :: String
--   youDirtyRat = "You dirty rat!\n" ++ youDirtyRat

{- New definitions from section 6.12 -}
    compareRat :: (Int -> Int -> Bool) -> Rat -> Rat -> Bool 
    compareRat r (a,b) (c,d) 
        |  b == 0    = errRat (a,0) 
        |  d == 0    = errRat (c,0) 
        |  otherwise = r (a*d) (b*c) 

    eqRat,neqRat,ltRat,leqRat,gtRat,geqRat :: Rat -> Rat -> Bool 
    eqRat   = compareRat (==) 
    neqRat  = compareRat (/=) 
    ltRat   = compareRat (<)  
    leqRat  = compareRat (<=) 
    gtRat   = compareRat (>)  
    geqRat  = compareRat (>=)
