Reputation: 1549
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
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 Exp
s into Value
s 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 Exp
s 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 Primitive
s 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 Value
s, 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
Value
s to behave like Bool
s in your language (like python), or should only Bool
Value
s behave like Bool
s?
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
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
Reputation: 36339
You want something like
let e' = {- extend env with x -} in eval e' y
Upvotes: 1