module FPPrac.Prelude.Number
( Number(..)
)
where
import Text.ParserCombinators.Parsec
import qualified Text.ParserCombinators.Parsec.Token as PT
import Text.ParserCombinators.Parsec.Language (emptyDef)
data Number
= I Integer
| F Double
instance Eq Number where
(I i1) == (I i2) = i1 == i2
(F f1) == (F f2) = f1 == f2
(I i1) == (F f2) = fromIntegral i1 == f2
(F f1) == (I i2) = f1 == fromIntegral i2
instance Ord Number where
compare (I i1) (I i2) = compare i1 i2
compare (F f1) (F f2) = compare f1 f2
compare (I i1) (F f2) = compare (fromIntegral i1) f2
compare (F f1) (I i2) = compare f1 (fromIntegral i2)
instance Show Number where
show (I i) = show i
show (F f) = show f
instance Num Number where
(I i1) + (I i2) = I (i1 + i2)
(F f1) + (F f2) = F (f1 + f2)
(I i1) + (F f2) = F ((fromInteger i1) + f2)
(F f1) + (I i2) = F (f1 + (fromInteger i2))
(I i1) * (I i2) = I (i1 * i2)
(F f1) * (F f2) = F (f1 * f2)
(I i1) * (F f2) = F ((fromInteger i1) * f2)
(F f1) * (I i2) = F (f1 * (fromInteger i2))
negate (I i) = I (negate i)
negate (F f) = F (negate f)
abs (I i) = I (abs i)
abs (F f) = F (abs f)
signum (I i) = I (signum i)
signum (F f) = F (signum f)
fromInteger = I
instance Real Number where
toRational (I i) = toRational i
toRational (F f) = toRational f
instance Enum Number where
toEnum = I . toInteger
fromEnum (I i) = fromEnum i
fromEnum (F f) = fromEnum f
instance Integral Number where
quotRem (I i1) (I i2) = let (i1',i2') = quotRem i1 i2 in (I i1', I i2')
quotRem (F _) _ = error "quotRem: first argument is not an integer"
quotRem _ (F _) = error "quotRem: second argument is not an integer"
divMod (I i1) (I i2) = let (i1',i2') = divMod i1 i2 in (I i1', I i2')
divMod (F _) _ = error "divMod: first argument is not an integer"
divMod _ (F _) = error "divMod: second argument is not an integer"
toInteger (I i) = i
toInteger (F _) = error "Can not use 'toInteger' to convert float to integer"
instance Fractional Number where
(/) (I i1) (I i2) = F $ (fromInteger i1) / (fromInteger i2)
(/) (F d1) (F d2) = F $ d1 / d2
(/) (F d1) (I i2) = F $ d1 / (fromInteger i2)
(/) (I i1) (F d2) = F $ (fromInteger i1) / d2
fromRational = F . fromRational
instance RealFrac Number where
properFraction (F f) = let (b,a) = properFraction f in (b, F a)
properFraction (I i) = let (b,a) = properFraction (fromIntegral i) in (b, F a)
truncate (F f) = truncate f
truncate (I i) = truncate ((fromIntegral i) :: Float)
round (F f) = round f
round (I i) = round ((fromIntegral i) :: Float)
ceiling (F f) = ceiling f
ceiling (I i) = ceiling ((fromIntegral i) :: Float)
floor (F f) = floor f
floor (I i) = floor ((fromIntegral i) :: Float)
instance Floating Number where
pi = F pi
exp (F f) = F (exp f)
exp (I i) = F (exp $ fromIntegral i)
sqrt (F f) = F (sqrt f)
sqrt (I i) = F (sqrt $ fromIntegral i)
log (F f) = F (log f)
log (I i) = F (log $ fromIntegral i)
(F f1) ** (F f2) = F (f1 ** f2)
(I i1) ** (I i2) = F ((fromIntegral i1) ** (fromIntegral i2))
(F f1) ** (I i2) = F (f1 ** (fromIntegral i2))
(I i1) ** (F f2) = F ((fromIntegral i1) ** f2)
logBase (F f1) (F f2) = F (logBase f1 f2)
logBase (I i1) (I i2) = F (logBase (fromIntegral i1) (fromIntegral i2))
logBase (F f1) (I i2) = F (logBase f1 (fromIntegral i2))
logBase (I i1) (F f2) = F (logBase (fromIntegral i1) f2)
sin (F f) = F (sin f)
sin (I i) = F (sin $ fromIntegral i)
tan (F f) = F (tan f)
tan (I i) = F (tan $ fromIntegral i)
cos (F f) = F (cos f)
cos (I i) = F (cos $ fromIntegral i)
asin (F f) = F (asin f)
asin (I i) = F (asin $ fromIntegral i)
atan (F f) = F (atan f)
atan (I i) = F (atan $ fromIntegral i)
acos (F f) = F (acos f)
acos (I i) = F (acos $ fromIntegral i)
sinh (F f) = F (sinh f)
sinh (I i) = F (sinh $ fromIntegral i)
tanh (F f) = F (tanh f)
tanh (I i) = F (tanh $ fromIntegral i)
cosh (F f) = F (cosh f)
cosh (I i) = F (cosh $ fromIntegral i)
asinh (F f) = F (asinh f)
asinh (I i) = F (asinh $ fromIntegral i)
atanh (F f) = F (atanh f)
atanh (I i) = F (atanh $ fromIntegral i)
acosh (F f) = F (acosh f)
acosh (I i) = F (acosh $ fromIntegral i)
lexer :: PT.TokenParser st
lexer = PT.makeTokenParser emptyDef
naturalOrFloat :: CharParser st (Either Integer Double)
naturalOrFloat = PT.naturalOrFloat lexer
instance Read Number where
readsPrec _ = either (const []) id . parse parseRead' "" where
parseRead' = do a <- naturalOrFloat
rest <- getInput
return [(either I F a, rest)]