# Writing interpreters for functional programming languages

```
{-# LANGUAGE FlexibleContexts, FlexibleInstances, OverlappingInstances #-}
import Data.Map (Map)
import qualified Data.Map as Map
import Control.Monad.State
```

So far, we have seen how to write an interpreter for a simple imperative language with While loops. But what about something closer to home? What if you wanted to write an interpreter for Haskell? Or for Ocaml? Or Scheme?

Today we'll implement an interpreter for small purely functional language, that captures the essence of these languages, called FUN. Because that is what it will be.

The abstract syntax for this language is in the module FunSyntax as well as a parser and pretty-printer for a concrete syntax.

`import FunSyntax `

## An Interpreter for FUN

In some sense, writing an interpreter for FUN is *easier* than writing one for WHILE. Recall that in our interpreter for the WHILE language, we leaned on Haskell structures to implement similar functionality for the object language. For example, we used Haskell integer and boolean values to represent WHILE's integer and boolean values; and we used Haskell's plus operator to implement WHILE's Plus.

We'll use that trick again to implement higher-order functions. To extend the datatype of values with function values, we'll just use Haskell functions. Just like we mapped WHILE integers to Haskell integers, we'll map FUN functions to Haskell functions.

```
data Value =
IntVal Int
| BoolVal Bool
-- new! function values
| FunVal (Value -> Value)
```

```
instance Show Value where
show (IntVal i) = show i
show (BoolVal b) = show b
show (FunVal _) = "<function>"
```

Now, on to the interpreter itself. Some parts we'll reuse, such as the evaluator for boolean operators

```
evalB :: Bop -> Value -> Value -> Value
evalB Plus (IntVal i1) (IntVal i2) = IntVal (i1 + i2)
evalB Minus (IntVal i1) (IntVal i2) = IntVal (i1 - i2)
evalB Times (IntVal i1) (IntVal i2) = IntVal (i1 * i2)
evalB Gt (IntVal i1) (IntVal i2) = BoolVal (i1 > i2)
evalB Ge (IntVal i1) (IntVal i2) = BoolVal (i1 >= i2)
evalB Lt (IntVal i1) (IntVal i2) = BoolVal (i1 < i2)
evalB Le (IntVal i1) (IntVal i2) = BoolVal (i1 <= i2)
evalB _ _ _ = IntVal 0
```

And the use of a finite map to keep track of the values of variables.

`type Store = Map Variable Value`

```
-- lookup variables in the store
slookup :: Variable -> Store -> Value
slookup x m = case (Map.lookup x m) of
Just v -> v
Nothing -> (IntVal 0)
```

Because we need to keep track of variables, we'll write the

interpreter using the `State`

monad as we did before.

```
evalS :: Expression -> State Store Value
evalS (Var x) = do
s <- get
return (slookup x s)
evalS (IntExp i) = return (IntVal i)
evalS (BoolExp i) = return (BoolVal i)
evalS (Op o e1 e2) = liftM2 (evalB o) (evalS e1) (evalS e2)
evalS (If e1 e2 e3) = do
v1 <- evalS e1
case v1 of
BoolVal b -> if b then evalS e2 else evalS e3
_ -> return (IntVal 0)
```

We need to update the variable mapping when we evaluate functions. The value of a function is a Haskell function, the argument of which provides the value of the variable in the body of the function.

`evalS (Fun x e) = undefined`

We can then evaluate a function application by applying the function value to its argument.

`evalS (App fun arg) = undefined`

Finally, in the case of a recursive definition for x, we need to evaluate the right-hand-side using a store that maps x to the value that we are currently computing ?! Whoa! We're using a Haskell recursive definition to define recursive definitions in FUN.

`evalS (LetRec x e1 e2) = undefined`

Let's give it a try!

`t0 = evalState (evalS factExp) Map.empty`

In fact, we can even create a simple REPL for evaluating expressions and showing their results. At the end of this file is the definition of a parser and pretty printer for the FUN language.

```
repl :: IO ()
repl = do
putStr "%> "
line <- getLine
case parse line of
Just exp -> do
putStrLn $ show (evalState (evalS exp) Map.empty)
repl
Nothing -> putStrLn "what?!?" >> repl
```

Wait a minute! Are we sure that we got the scoping right?

`t01 = parse "(let rec X = 1 in X) + X"`

Of course! When we are done with the body of a let rec expression, we need to remove the binding from the store so that it will no longer be available.

# An Environment-Passing interpreter

It turns out that the state monad is not exactly the right match for the interpreter above. In essence, our evaluator has the following type:

` evalS :: Expression -> Store -> (Value, Store)`

Every call to `evalS`

returns the new Store. However, our language is pure---there is no way to change the value of a FUN variable---so the fact that we get access to the resulting `Store`

is of no use to us. In fact, we deliberately have to throw it away in a few places.

Instead, let's rewrite our interpreter using the following type:

` evalE :: Expression -> Store -> Value`

We'll pass the current value of the store as an additional argument to the evaluator. When we extend the store, it is only temporary and follows the recursive structure of the evaluator itself. Which just so happens to match the lexical structure of the term. Nifty!

Since we are using this finite map in a fundamentally different way, we'll give it a new name.

`type Environment = Map Variable Value`

We can now rewrite the interpreter, so that every case takes an extra parameter (the environment).

```
evalE :: Expression -> Environment -> Value
evalE (Var x) s = slookup x s
evalE (IntExp i) s = IntVal i
evalE (BoolExp i) s = BoolVal i
evalE (Op o e1 e2) s = (evalB o) (evalE e1 s) (evalE e2 s)
evalE (If e1 e2 e3) s =
let v1 = evalE e1 s in
case v1 of
BoolVal b -> if b then evalE e2 s else evalE e3 s
_ -> (IntVal 0)
evalE (Fun x e) s = undefined
evalE (App fun arg) s = undefined
evalE (LetRec x e1 e2) s = undefined
```

However, what about that environment passing? We still have to manipulate it explicitly?!?

If only there was something that could help....

# The Reader Monad

It turns out that we can still write our interpreter in monadic style. We just need to use a different monad. The `Reader`

Monad is a type `r -> a`

, which captures the idea of reading shared values from a common environment. (There is a standard implementation of this monad the library `Control.Monad.Reader`

, including a monad transformer version of it. However, we'll build it up ourselves here.)

```
instance Monad ((->) Environment) where
return x = \s -> x
m >>= k = \s -> k (m s) s
```

With this monad, we can pass the environment around implicitly where it doesn't matter, yet still refer to it explicitly when necessary.

```
eval :: Expression -> Environment -> Value
eval (Var x) = undefined
```

```
eval (IntExp i) = return (IntVal i)
eval (BoolExp i) = return (BoolVal i)
eval (Op o e1 e2) = liftM2 (evalB o) (eval e1) (eval e2)
eval (If e1 e2 e3) = do
v1 <- eval e1
case v1 of
BoolVal b -> if b then eval e2 else eval e3
_ -> return (IntVal 0)
```

`eval (Fun x e) = undefined`

```
eval (App fun arg) = do
fv <- eval fun
av <- eval arg
case fv of
(FunVal f) -> return $ f av
_ -> return (IntVal 0)
```

`eval (LetRec x e1 e2) = undefined`

## A note about evaluation order

We've implemented an environment passing interpreter for FUN, using many of the Haskell language features as direct implementations of the features of FUN.

That means that FUN, like Haskell, has call-by-need semantics. The arguments of functions are not evaluated until they are needed. In this pure language, the only way to observe this, is through infinite loops.

For example, we can define an infinitely looping function using let rec. Just creating the function won't cause our program to diverge.

`t2 = "let rec LOOP = fun Y -> LOOP Y in LOOP"`

However, if we ever call this function, we will be in for trouble.

`t3 = "let rec LOOP = fun Y -> LOOP Y in LOOP 3"`

This infinite loop shows how evaluation order makes a difference. Because FUN is like Haskell, this expression does terminate. But if it were call-by-value (like OCaml or Scheme) it would still diverge.

`t4 = "let rec LOOP = fun Y -> LOOP Y in (fun Z -> 2) (LOOP 3)"`

So, that raises the question, what if we wanted FUN to have a call-by-value semantics?

## News :

Welcome to CIS 552!

See the home page for basic
information about the course, the schedule for the lecture notes
and assignments, the resources for links to the required software
and online references, and the syllabus for detailed information about
the course policies.