I'm attempting to define an evaluator for the language E and to be quite frank I'm completely at a loss for how to fix all the errors I keep getting with how the eval type is defined. I've spent several hours now reading up on interpreters, monads and trying to find something similar to give me a basis but I've turned up nothing. This is homework so naturally no straight out answers please. My big problems right now are the fact that there are no instance declarations for Num E or Integral E and when I've tried using fromInt and fromNum to fix this I'm met with additional errors. I've also tried changing the definitions to all sorts of different ways, the main problem with those being that Int doesn't match the type of E. I feel like I'm missing something pretty basic but I haven't been able to narrow it down at all. I'll be happy to answer any other questions if I wasn't clear on any particular points. If there are any sources that would be good additional information I'd really appreciate links.
data E = IntLit Int
| BoolLit Bool
| Plus E E
| Minus E E
| Multiplies E E
| Divides E E
| Equals E E
deriving (Eq, Show)
eval :: E -> E
--eval = undefined
eval (IntLit a) = IntLit a
eval (BoolLit a) = BoolLit a
eval (Plus a b) = eval a + eval b
eval (Minus a b) = eval a - eval b
eval (Multiplies a b) = eval a * eval b
eval (Divides a b) = eval a `div` eval b
eval (Equals a b) = BoolLit(a == b)
Monads have really nothing to do with this. Because you are mixing two types together: ints and bools, you either need to use some type hackery (GADTs) and define eval with type:
eval :: E a -> a
or define a new type called Value like this:
data Value = IntValue Int | BoolValue Bool | TypeError
and then have:
eval :: E -> Value
Inside eval, you need to match results of your expressions like this:
eval (Plus e1 e2) = case eval e1 of
(IntValue v1) -> case eval e2 of
(IntValue v2) -> IntValue (v1+v2)
_ -> TypeError
_ -> TypeError
This is tedious, but simple. :) Of course you don't want to repeat yourself many times, so save yourself a lot of work by defining a helper function:
evalMathBinOp :: (Int -> Int -> Int) -> E -> E -> Value
evalMathBinOp f e1 e2 = case eval e1 of
(IntValue v1) -> case eval e2 of
(IntValue v2) -> IntValue (f v1 v2)
_ -> TypeError
_ -> TypeError
and now just:
eval (Plus e1 e2) = evalMathBinOp (+) e1 e2
eval (Minus e1 e2) = evalMathBinOp (-) e1 e2
-- and so on...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With