module Aexp where --------------------------------- -- the language of expressions -- --------------------------------- type Number = Int data Operator = Plus | Minus | Mult | Div deriving Show data Expression = N Number | Exp Expression Operator Expression deriving Show ------------------------------ -- some example expressions -- ------------------------------ e1 = N 1 -- 1 e2 = Exp (N 1) Plus (N 2) -- 1 + 2 e3 = Exp e2 Mult e1 -- (1 + 2) * 1 e4 = Exp e3 Div (N 0) --------------------- -- the interpreter -- --------------------- eval :: Expression -> Number eval (N n) = n eval (Exp e1 Plus e2) = (eval e1) + (eval e2) eval (Exp e1 Minus e2) = (eval e1) - (eval e2) eval (Exp e1 Mult e2) = (eval e1) * (eval e2) eval (Exp e1 Div e2) = (eval e1) `div` (eval e2) -- eval (Exp e1 Div e2) = div (eval e1) (eval e2) {- div is a function, `div` is an operator -} {- Check out what happens if you use the following function equation eval (Exp e1 Div e2) = (eval e1) / (eval e2) -} -- some variations (local definitions) eval' :: Expression -> Int eval' (N n) = n eval' (Exp e1 op e2) = f op (eval' e1) (eval' e2) where f Plus e1 e2 = e1 + e2 f Minus e1 e2 = e1 - e2 f Mult e1 e2 = e1 * e2 f Div e1 e2 = e1 `div` e2 -- or eval'' :: Expression -> Int eval'' (N n) = n eval'' (Exp e1 op e2) = let f Plus e1 e2 = e1 + e2 f Minus e1 e2 = e1 - e2 f Mult e1 e2 = e1 * e2 f Div e1 e2 = e1 `div` e2 in f op (eval'' e1) (eval'' e2) -- extensions, we want to catch division by zero data Res a = Err String | Res a deriving Show {- deriving Show tells hugs how to print user-defined values -} evalE :: Expression -> Res Int evalE (N n) = Res n evalE (Exp e1 Plus e2) = case (evalE e1) of Res v1 -> case (evalE e2) of Res v2 -> Res (v1 + v2) Err text -> Err text Err txt -> Err txt evalE (Exp e1 Minus e2) = case (evalE e1) of Res v1 -> case (evalE e2) of Res v2 -> Res (v1 - v2) Err text -> Err text Err txt -> Err txt evalE (Exp e1 Mult e2) = case (evalE e1) of Res v1 -> case (evalE e2) of Res v2 -> Res (v1 * v2) Err text -> Err text Err txt -> Err txt evalE (Exp e1 Div e2) = case (evalE e1) of Res v1 -> case (evalE e2) of Res v2 -> if v2 == 0 then Err "division by zero" else Res (v1 `div` v2) Err text -> Err text Err txt -> Err txt -- or -- some magic!! instance Monad Res where m >>= k = case m of Res a -> k a Err t -> Err t return x = Res x -- imperative style interpreter in Haskell evalE' :: Expression -> Res Int evalE' (N n) = return n evalE' (Exp e1 Plus e2) = do v1 <- evalE' e1 -- v1= evalE' e1 ; v2 <- evalE' e2 -- v2= evalE' e2 ; return (v1 + v2) -- return (v1 + v2) ; evalE' (Exp e1 Minus e2) = do v1 <- evalE' e1 v2 <- evalE' e2 return (v1 - v2) evalE' (Exp e1 Mult e2) = do v1 <- evalE' e1 v2 <- evalE' e2 return (v1 * v2) evalE' (Exp e1 Div e2) = do v1 <- evalE' e1 v2 <- evalE' e2 if v2 == 0 then Err "division by zero" else return (v1 `div` v2)