{-  Exploring Languages with Interpreters and Functional Programming
    Chapters 7 & 17 -- Higher Order Rational Arithmetic Module (outer)
    Copyright (C) 2018, H. Conrad Cunningham

1234567890123456789012345678901234567890123456789012345678901234567890

2016-07-??: Based on SICP 2.1 & my earler Haskell, Lua versions
2018-06-12: Added "zeroRat" and divide by zero check
2018-07-04: Added copyright notice
2018-07-11: Fixed bug in divRat (incorrect divide by zero).
            Added exports of relational operators
2018-07-19: Updated for compatibility with Chapter 17

-}

module RationalHO
  ( Rat, zeroRat, makeRat, numer, denom, showRat,
    negRat, addRat, subRat, mulRat, divRat,
    eqRat, neqRat, ltRat, leqRat, gtRat, geqRat
  )
where

-- Select needed data representation module
import RationalCore
-- import RationalDeferGCD

-- First-order Operations

negRat :: Rat -> Rat 
negRat x = makeRat (- numer x) (denom x)

addRat, subRat, mulRat, divRat :: Rat -> Rat -> Rat 
addRat x y = makeRat (numer x * denom y + numer y * denom x)
                     (denom x * denom y) 
subRat x y = makeRat (numer x * denom y - numer y * denom x)
                     (denom x * denom y) 
mulRat x y = makeRat (numer x * numer y) (denom x * denom y) 
divRat x y
    | eqRat y zeroRat = error "Attempt to divide by 0"
    | otherwise       = makeRat (numer x * denom y)
                                (denom x * numer y) 

-- REDEFINED from Rational (first order version)
-- eqRat :: Rat -> Rat -> Bool 
-- eqRat x y = (numer x) * (denom y) == (numer y) * (denom x)      

-- ADDED to Rational (higher-order version)
compareRat :: (Int -> Int -> Bool) -> Rat -> Rat -> Bool 
compareRat r x y = r (numer x * denom y) (denom x * numer y) 

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