Haskell mini-language

I am trying to define an evaluator for the E language and be frank. I'm completely at a loss as to how to fix all the errors I keep getting with the eval type definition. I spent several hours reading translators, monads and trying to find something similar to give me a foundation, but I didn't get it. This is homework, so naturally there are no direct answers. My big problems right now is that there are no instance declarations for Num E or Integral E, and when I tried to use fromInt and fromNum to fix this, I was met with additional errors. I've also tried changing the definitions in all sorts of ways, the main problem is that the Int doesn't match the type E. I feel like I'm missing something pretty simple, but I haven't been able to narrow it down at all. I will be happy to answer any other questions,if I do not understand any specific points. If there are any sources that would be good additional information, I would love the 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)



source to share

1 answer

Monads have nothing to do with this. Since you are mixing the two types together, ints and bools, you either need to use type specific hackers (GADT) or define eval with the type:

eval :: E a -> a


or define a new type called Value

like this:

data Value = IntValue Int | BoolValue Bool | TypeError


and then:

eval :: E -> Value


Inside eval, you need to match the 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


It's tedious but simple. :) Of course you don't want to repeat yourself many times, so save 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 it's simple:

eval (Plus e1 e2) = evalMathBinOp (+) e1 e2
eval (Minus e1 e2) = evalMathBinOp (-) e1 e2
-- and so on...




All Articles