Reputation: 2066
As part of defining a language interpreter I have the following definition:
initCtx :: Context
initCtx = (Map.empty, initEnv)
where initEnv =
Map.fromList [ ...
, ("+", undefined)
...
]
And for the sum operation I have this:
evalExpr :: Expr -> Interpreter Value
evalExpr (e1 :+: e2) = do v1 <- eval e1
v2 <- eval e2
return Interpreter $ (v1 + v2)
The exalExpr is made by me, but what do I need to write in place of undefined
so that the expression is executed? Or, perhaps, I am looking to the wrong thing ? I have more operations of course, but I just need to have an example. I am veeeeery new to Haskell, I am practically required to deal with it.
Thanks!
EDIT:
type Env = Map Ident Value
type Primitive = [Value] -> Interpreter Value
type PEnv = Map FunName Primitive
type Context = (Env, PEnv)
Here's Expr
:
data Expr = Number Int
| String String
| Array [Expr]
| Undefined
| TrueConst
| FalseConst
| Var Ident
| Compr ArrayFor Expr
| Call FunName [Expr]
| Assign Ident Expr
| Comma Expr Expr
deriving (Eq, Read, Show)
And Interpreter
newtype Interpreter a = Interpreter {runInterpreter :: Context -> Either Error (a, Env)}
And Value:
data Value = IntVal Int
| UndefinedVal
| TrueVal | FalseVal
| StringVal String
| ArrayVal [Value]
deriving (Eq, Show)
Upvotes: 0
Views: 345
Reputation: 62868
Alright, I'll take a stab at this...
So it looks like a Context
consists of a pair of maps. It appears the first map lets you look up a variable's value from its name. The second one lets you look up a function name and get the corresponding executable code for it.
You're using Interpreter
as if it's a monad; I don't know whether it actually is, but it looks plausible.
So initCtx
starts off with no variables defined (Map.empty
), and presumably you're meant to put a bunch of predefined functions like +
in the second map.
Looking at the definition for Primitive
, it takes a list of Value
and returns an Interpreter
computation. So I guess it looks something like
addExpr :: [Value] -> Interpreter Value
addExpr [e1, e2] = do
v1 <- eval e1
v2 <- eval e2
return (v1 + v2)
and then you could write map.fromList [... ("+", addExpr) ...]
.
Except that's not quite right either. Value
isn't a number type; what happens if, say, v1 = StringVal
? For that matter, what if somebody calls "+" with a different number of arguments? We need some error checking here.
I'm guessing the thing you're looking for probably looks something like this:
checkInt :: Value -> Interpreter Int
checkInt (IntVal x) = return x
checkInt _ = Interpreter $ ctx -> Left "Not an integer."
addExpr :: [Value] -> Interpreter Value
addExpr [expr1, expr2] do
val1 <- eval expr1
int1 <- checkInt val1
val2 <- eval expr2
int2 <- checkInt val2
return (IntVal $ int1 + int2)
addExpr _ = Interpreter $ ctx -> error "Wrong number of arguments."
Upvotes: 1