module Eval (eval,getPrec) where import BasicNumber import BasicNumberApprox import Ast import Env -- eval takes an expression and environment, tries to reduce the expression, -- and returns the reduced expression. eval :: BasicExp -> Env -> BasicExp eval (EVar evar) env = eval (lookupEnv evar env) env eval (Func name args) env = case args of [] -> Func name [] [arg] -> eval_func_1 name arg env [arg1,arg2] -> eval_func_2 name arg1 arg2 env args -> eval_func_n name args env eval bexp env = bexp -- get precision from the environment getPrec :: Env -> Integer getPrec env = prec where prec = read (show bprec) bprec = case pexpr of (Numb n) -> -n _ -> -10 pexpr1 = lookupEnv "$prec" env pexpr = eval pexpr1 env -- evaluate functions with 1 argument. eval_func_1 :: String -> BasicExp -> Env -> BasicExp eval_func_1 name arg env = if isBuiltin1 name then (getBuiltin1 name) narg (getPrec env) else Func name [narg] where narg = eval arg env -- evaluate functions with 2 arguments. eval_func_2 :: String -> BasicExp -> BasicExp -> Env -> BasicExp eval_func_2 name arg1 arg2 env = if isBuiltin2 name then (getBuiltin2 name narg1 narg2) narg1 narg2 (getPrec env) else Func name [narg1,narg2] where narg1 = eval arg1 env narg2 = eval arg2 env -- evaluate functions with n(n>2) arguments. eval_func_n :: String -> [BasicExp] -> Env -> BasicExp eval_func_n name args env = Func name nargs where nargs = map eval_element args eval_element elem = eval elem env -- test if a function is builtin of arity 1 isBuiltin1 :: String -> Bool isBuiltin1 "sqrt" = True isBuiltin1 "real" = True isBuiltin1 "rat" = True isBuiltin1 "neg" = True isBuiltin1 _ = False -- get a builtin function with 1 argument getBuiltin1 :: String -> (BasicExp -> Integer -> BasicExp) getBuiltin1 "sqrt" = aBnf2Bef1 "sqrt" sqrt1 where sqrt1 :: BasicNumber -> Integer -> BasicNumber sqrt1 n _ = sqrt n getBuiltin1 "real" = aBnf2Bef1 "real" makeReal1 where makeReal1 :: BasicNumber -> Integer -> BasicNumber makeReal1 n _ = makeReal n getBuiltin1 "rat" = aBnf2Bef1 "rat" rtoRational getBuiltin1 "neg" = aBnf2Bef1 "neg" negation where negation :: BasicNumber -> Integer -> BasicNumber negation x _ = 0-x -- convert arithmetic functions on numbers to those on expressions aBnf2Bef1 :: String -> (BasicNumber -> Integer -> BasicNumber) -> (BasicExp -> Integer -> BasicExp) aBnf2Bef1 name fun arg prec = case arg of (Numb n) -> Numb (fun n prec) _ -> (Func name [arg]) -- test if a function is builtin of arity 2 isBuiltin2 :: String -> Bool isBuiltin2 "add" = True isBuiltin2 "sub" = True isBuiltin2 "mul" = True isBuiltin2 "div" = True isBuiltin2 "equ" = True isBuiltin2 "ne" = True isBuiltin2 "gte" = True isBuiltin2 "lte" = True isBuiltin2 "lt" = True isBuiltin2 "gt" = True isBuiltin2 _ = False -- get a builtin function with 2 arguments getBuiltin2 :: String -> BasicExp -> BasicExp -> (BasicExp -> BasicExp -> Integer -> BasicExp) getBuiltin2 "add" _ _ = aBnf2Bef "add" (+) getBuiltin2 "sub" _ _ = aBnf2Bef "sub" (-) getBuiltin2 "mul" _ _ = aBnf2Bef "mul" (*) getBuiltin2 "div" _ _ = aBnf2Bef "div" (/) getBuiltin2 "equ" _ _ = bBnf2Bef "equ" equ getBuiltin2 "ne" _ _ = bBnf2Bef "ne" ne getBuiltin2 "lt" _ _ = bBnf2Bef "lt" lt getBuiltin2 "gt" _ _ = bBnf2Bef "gt" gt getBuiltin2 "gte" _ _ = bBnf2Bef "gte" gte getBuiltin2 "lte" _ _ = bBnf2Bef "lte" lte -- convert Haskell boolean to basic expression bool2bexp :: Bool -> BasicExp bool2bexp True = Numb 1 bool2bexp False = Numb 0 -- convert boolean functions on numbers to those on expressions bBnf2Bef :: String -> (BasicNumber -> BasicNumber -> Integer -> Bool) -> BasicExp -> BasicExp -> Integer -> BasicExp bBnf2Bef name fun e1 e2 prec = case (e1,e2) of ((Numb n1),(Numb n2)) -> bool2bexp (fun n1 n2 prec) _ -> (Func name [e1,e2]) -- convert arithmetic functions on numbers to those on expressions aBnf2Bef :: String -> (BasicNumber -> BasicNumber -> BasicNumber) -> (BasicExp -> BasicExp -> Integer -> BasicExp) aBnf2Bef name fun arg1 arg2 _ = case (arg1,arg2) of ((Numb n1),(Numb n2)) -> Numb (fun n1 n2) _ -> (Func name [arg1, arg2])