Comforse
Comforse

Reputation: 2066

Haskell: define interpreter for language

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

Answers (1)

MathematicalOrchid
MathematicalOrchid

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

Related Questions