# Lecture 8 — 2015-09-28

## Call-by-value, call-by-name; interpreters

This lecture is written in literate Haskell; you can download the raw source.

**Small step semantics for the lambda calculus**

We talked about different stragegies for applying the equational semantics of the lambda calculus. We settled on two rewrite semantics for the lambda calculus: call-by-name, which is more like Haskell, and call-by-value, which is more like conventional languages.

The call-by-name semantics never bothers to evaluate its arguments. It just evalutes the *head* of each application, and then substitutes whatever arguments are there wholesale.

```
e1 --> e1'
---------------- CBNLeft
e1 e2 --> e1' e2
------------------------ CBNBeta
(\x. e1) e2 --> e1[e2/x]
```

The call-by-value semantics forces functions to evaluate their arguments, evaluating both sides of an application completely before doing beta reduction.

```
e1 --> e1'
---------------- CBVLeft
e1 e2 --> e1' e2
e2 --> e2'
---------------- CBVRight
v1 e2 --> v1 e2'
------------------------ CBVBeta
(\x. e1) v2 --> e1[v2/x]
```

**Big step semantics**

As we moved towards implementing our code, I said that substitution isn’t a great strategy. Instead, we’ll use environments.

We defined a *big* step semantics in math, which completely evaluates its inputs. The key new development here is *closures*, the combination of code—a lambda—and its environment.

Environments are maps from variable names to values, and values are closures. Here’s the full definition:

```
e in Term ::= x | \x. e | e1 e2
env in Env = Var -> Value
v in Value ::= <\x. e, env>
```

We defined a big-step rewrite system that evaluated everything in one go. I used something like ⇓. That’s hard to typeset here, so I’ll use `VV`

. Here `VV`

∈ **2**^{Term × Env × Value}.

Each rule takes a term and its current environment to a value. The rule for variables is easy: just look up the variable in the environment!

```
env(x) = v
----------- Var
x, env VV v
```

The rule for lambdas is also easy: they just become closures, holding onto the environment in which they were defined.

```
-------------------------- Lam
\x. e, env VV <\x. e, env>
```

The interesting rule is for applications. We evaluate each of the subterms in the current environment, `env`

. Whatever term is in the function position—e_{1}—must evaluate to a closure, `<\x. e, env'>`

. We then run the body of the closure—`e`

—in the closure’s environment extended with `v2`

bound for `x`

. (We write `env[x |-> v2]`

to talk about extending the environment.)

```
e1, env VV <\x. e, env'> e2, env VV v2
e,env'[x |-> v2] VV v
----------------------------------------- App
e1 e2, env VV v
```

**Moving to code**

Substitution is annoying to implement. Let’s use a different strategy: *environments*.

```
import qualified Data.Map as Map
import Data.Map (Map, (!))
```

The pure lambda calculus has three forms: variables, applications, and lambda abstractions.

```
type Id = String
data LCExpr =
LCVar Id
| LCApp LCExpr LCExpr
| LCLam Id LCExpr
deriving (Show,Eq)
```

We define values and environment mutually recursively: the only kind of values are closures (which have environments); environments are maps from variable names to values (which must be closures, which have environments, etc.).

```
data LCValue =
Closure Id LCExpr Env deriving Eq
type Env = Map Id LCValue
instance Show LCValue where
show (Closure x e _) = "\\" ++ x ++ ". " ++ show e
extend :: Env -> Id -> LCValue -> Env
extend env x v = Map.insert x v env
```

Can you relate each part of this definition to something in the math?

```
evalLC :: Env -> LCExpr -> LCValue
evalLC env (LCVar x) = env ! x
evalLC env (LCLam x e) = Closure x e env
evalLC env (LCApp e1 e2) =
case evalLC env e1 of
Closure x e env' -> evalLC (extend env' x (evalLC env e2)) e
```