0

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.

5
  • 1
    eval e (Let [x] y) = let (let fst x = snd x) = y What do you mean that line to do? That isn't even syntactically correct. The use let is invalid with an in EXPR (except in do notation, but that's just sugar). Commented Feb 2, 2013 at 4:12
  • I ment let is invalid without in. Commented Feb 2, 2013 at 4:20
  • okay. If you look at the test cases in main, eval takes env, and exp. env has the form of [(String, Value)]. String becomes a variable which has a value of Value, and that variable goes into env... that's what I meant. But I guess that's not what my code means. Commented Feb 2, 2013 at 4:28
  • 1
    possible duplicate of Haskell: parse error on input `=' Commented Feb 2, 2013 at 4:29
  • I must have misunderstood what Let exactly does. Commented Feb 2, 2013 at 19:25

3 Answers 3

4

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...

Sign up to request clarification or add additional context in comments.

9 Comments

Thank you for the lengthy and detailed explanation, but I still don't understand something about primitive. That is, if I have "Primitive Add [(Literal (Number 13)), (Literal (Number 12))])" this will cause "prim Add [ e exp]." The exp is not a list in prim, so it takes only one exp, although I have two. So, because of that even this simple test case won't run with my code.
The Primitive constructor takes an Op and a list of Exp. In your eval function, you can pattern match on the Primitive constructor as eval env (Primitive op args) = ..., so that the Op will be bound to op, and the list of Exp will be bound to args. The prim function wants a list of Values, so you will need to map eval over the args with map (eval env) args. You can then pass op, and the resulting list of Values to prim. i.e. eval env (Primitive op args) = prim op $ map (eval env) args.
I wasn't trying to be vague or give hints. The exact line of code you need is what I wrote at the end of my previous comment! Maybe the dollar sign is tripping you up. It is equivalent to the following: eval env (Primitive x y) = prim x (map (eval env) y). Please note that there is not a square-bracket in sight.
Your Let handler is still messed up too. It will only match when there is a single binding, and then proceeds to ignore the binding and evaluate the expression. Try something like: eval env (Let bs exp) = eval (map (\(lhs,rhs) -> (lhs, eval env rhs)) bs ++ env) exp
Cool. I created a cleaned up version here, but it will only stay there for 1 day. Note that the single-quote prime characters are tripping up the syntax hilighter.
|
3

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")]))

4 Comments

I would also like to warn about the expression [x] on the left side of an equation, ie. pattern matching on the list type, matches lists of exactly one element only.
Thank you so much, I've been agonizing over 5 hours on this assignment. But when I run it, I get this message: "Non-exhaustive patterns in function eval." How am I supposed to handle this error? and what does this error mean? Thank you so much.
I see what the problem is. When I run that test case, that's going to crash when it hits "eval e (Variable x) = fromJust (lookup x e)," because it returns nothing. The "e" which means environment should contain more than a single tuple, but I have no idea how to add tuples to that, and I am afraid that that'd violate the Env condition, which is "type Env = [(String, Value)]." I suppose that it means it can contain only one tuple in the list, right?
"eval e (Primitive x [y]) = prim x [eval e y]" I think this code causes a lot of problems, because [y] is a list of Expressions, and the code turn it into just a single expression.
1

You want something like

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.