Nayana
Nayana

Reputation: 1549

Haskell parse error

I am not exactly sure what I am doing wrong. I am stuck and I can't make anymore progress.

I put the error message I get in my code in comment. If time allows, could someone please check my eval function? I think I am doing something terribly wrong.

Thank you.

Upvotes: 0

Views: 785

Answers (3)

pat
pat

Reputation: 12749

Your Let handler will need to extend the environment with the new bindings, and then evaluate the expression with that new environment.

Your environment is a list of name, Value pairs, but the Let contains a list of name, Exp pairs, so you will need to convert the Exps into Values in order to extend the environment. Note that eval converts an Exp into a Value.

However, since the Let can hold multiple bindings, you will need to decide whether the Exps are evaluated in parallel, or sequentially (the difference between let and let* in lisp). Can a binding affect the value of following bindings? Depending upon the answer to that question, you will find yourself using either map or foldl to transform the list.

Your problem with the evaluation of Primitives is twofold. First, you are using a pattern which will only match against a list of exactly one element, but your primitives obviously take different numbers of arguments. The pattern should not use list syntax, since the Primitive constructor guarantees that there will be a list in that position. Instead, you should use a pattern that matches anything (like plain y). Second, the prim function is expecting a list of Values, but the Primitive constructor contains a list of Exp, so you will need to convert them (however, since evaluation of the arguments does not affect the environment, you will be using map).

To get you going in the right direction, in:

eval e (Primitive x [y]) = prim x [eval e y]

the [y] pattern will match only a single element list, with that element bound to y, and [eval e y] is going to result in a single element list. What you want is a pattern that matches the whole list, and then you want to transform that list by applying eval e to each element of that list.

The eval of If also has problems. The condition, the then, and the else are all of type Exp, but eval is supposed to return a Value, so you will have to transform something. Finally, the haskell if wants the condition to be a haskell Bool, but your condition is an Exp. You will need to evaluate the Exp into a Value, and then somehow extract a haskell Bool from the Value. Do you want Number and String Values to behave like Bools in your language (like python), or should only Bool Values behave like Bools?

Finally, finally, if you have any type errors (like trying to Add a String to a Number), or you supply the wrong number of arguments to a primitive, you are going to get a pattern match failure from the prim function (and possibly in the code you will have to write to extract a Bool from your If condition). That may or may not be what you want...

Upvotes: 4

David Unric
David Unric

Reputation: 7719

as Thomas M. DuBuisson already said, your let expression has invalid syntax. Second you really have to be aware what type of arguments function takes and what type it returns. You can not mix Exp with Value, for example - where Exp type is expected you have always pass value of Exp type etc.

eval :: Env -> Exp -> Value
-- the return type is Value
-- what are you trying to do here ? extract Value from x ...
eval e (Let [x] y) = eval e $ snd x
-- ... or from y ? Both x & y are of Exp type.
eval e (Let [x] y) = eval e y

There are also more type errors in your code:

eval e (Primitive x [y]) = prim x [y]
-- prim expects 2nd argument of [Value] type so it can be written as
eval e (Primitive x [y]) = prim x [eval e y]
-- dtto, mixing different types is wrong
eval e (If x y z) = if x then y else z
eval e (If x y z) = let Bool x' = eval e x in
                        if x' then (eval e y) else (eval e z)

and finally main expects IO () as the return type so you have to reflect this somehow, like printing the eval result:

print $ eval [("y", (Number 40))] (Let [("x", (Literal (Number 2)))] (Primitive Add [(Variable "x"), (Variable "y")]))

Upvotes: 3

Ingo
Ingo

Reputation: 36339

You want something like

let e' = {- extend env with x -} in eval e' y 

Upvotes: 1

Related Questions