{-# LANGUAGE RankNTypes #-} module RealCalc (calculate) where import qualified Expr data Result = RInt Integer | RFloat Double instance Show Result where show (RInt i) = show i show (RFloat d) = show d rToDouble :: Result -> Double rToDouble (RInt i) = fromIntegral i rToDouble (RFloat d) = d genericCombine :: (forall a. Num a => a -> a -> a) -> Result -> Result -> Result genericCombine f i j = case (i, j) of (RInt a, RInt b) -> RInt (f a b) _ -> RFloat (f (rToDouble i) (rToDouble j)) genericInner :: (forall a. Num a => a -> a) -> Result -> Result genericInner f (RInt i) = RInt (f i) genericInner f (RFloat d) = RFloat (f d) simplify :: Expr.Expr -> Result simplify (Expr.Plus e1 e2) = genericCombine (+) (simplify e1) (simplify e2) simplify (Expr.Negate e) = genericInner negate (simplify e) simplify (Expr.Minus e1 e2) = genericCombine (-) (simplify e1) (simplify e2) simplify (Expr.Times e1 e2) = genericCombine (*) (simplify e1) (simplify e2) simplify (Expr.Div e1 e2) = RFloat (rToDouble (simplify e1) / rToDouble (simplify e2)) simplify (Expr.EInt i) = RInt i simplify (Expr.EFloat d) = RFloat d simplify Expr.E = RFloat (exp 1) simplify Expr.Pi = RFloat pi simplify (Expr.Log e) = RFloat . log . rToDouble $ simplify e simplify (Expr.Sin e) = RFloat . sin . rToDouble $ simplify e simplify (Expr.Cos e) = RFloat . cos . rToDouble $ simplify e simplify (Expr.Sqrt e) = RFloat . sqrt . rToDouble $ simplify e calculate :: String -> Maybe String calculate s = case Expr.parseE s of Left _ -> Nothing Right e -> Just . show $ simplify e