# Homework 4

## Lambda calculus interpreter

This homework is written in literate Haskell; you can download the raw source to fill in yourself. You’re welcome to submit literate Haskell yourself, or to start fresh in a new file, literate or not.

Please submit homeworks via the DCI submission page.

NOTE: This homework will be due on Friday, October 2nd, since I didn’t post it until Saturday.

``````module Hw04 where

import Prelude hiding (succ,pred)

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

Problem 1: pure lambda calculus

We’ll just have variable names be strings.

``type Id = String``

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

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

Write a function `freeVars` that collects the set of free variables in a given lambda calculus expression.

``````freeVars :: LCExpr -> Set Id
freeVars = undefined``````

Write a function `wellScoped` that determines whether or not a given lambda calculus is well scoped, i.e., there.

``````wellScoped :: LCExpr -> Bool
wellScoped = undefined``````

Here we’ve defined a simple, environment-based lambda calculus interpreter, just like we’ve looked at in class on Monday.

``````data LCValue = Closure Id LCExpr (Env LCValue) deriving Eq
type Env a = Map Id a

extend :: Env a -> Id -> a -> Env a
extend env x v = Map.insert x v env

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

runLC :: LCExpr -> LCValue
runLC = evalLC Map.empty``````

We’re going to implement some of the Church numeral material we’ve seen in class. Here are the initial definitions:

``````true  = LCLam "x" (LCLam "y" (LCVar "x"))
false = LCLam "x" (LCLam "y" (LCVar "y"))
cond  = LCLam "p" (LCLam "t" (LCLam "e" (LCApp (LCApp (LCVar "p") (LCVar "t")) (LCVar "f"))))

zero = LCLam "s" (LCLam "z" (LCVar "z"))
succ = LCLam "n" (LCLam "s" (LCLam "z"
(LCApp (LCVar "s") (LCApp (LCApp (LCVar "n") (LCVar "s")) (LCVar "z")))))``````

This is a little annoying. Surely we can make these kinds of definitions easier! Write a function `lam` that takes a list of variable names and a function body and produces a series of nested lambda expressions around that body. For example `lam ["s","z"] (LCVar "z")` should yield the value for `zero`.

If `lam` is called with an empty `args` list, it should just return the `body`.

``````lam :: [Id] -> LCExpr -> LCExpr
lam args body = undefined``````

Write a similar function, `app`, that takes a list of expressions and produces an appropriately nested application. For example, `lam ["n","s","z"] (app [LCVar "s",app [LCVar "n",LCVar "s",LCVar "z"]])` should yield the value for `succ`.

What should `app` do when called with no arguments? Is there a value that’s generally ‘safe’ to return here?

``````app :: [LCExpr] -> LCExpr
app es = undefined``````

With these helper functions to hand, complete the following definitions for Church numerals. You can of course use any of the foregoing functions.

``````isZero, plus, times :: LCExpr
isZero = undefined
plus = undefined
times = undefined``````

Here is the Church encoding for pairs.

``````pair = lam ["a","b","c"] \$ app \$ map LCVar ["c","a","b"]
first = lam ["c"] \$ app [LCVar "c", true]
second = lam ["c"]\$ app [LCVar "c", false]``````

Now define the predecessor function, `pred`, and subtraction, `sub`.

``````pred, sub :: LCExpr
pred = undefined
sub = undefined``````

Problem 2: lambda calculus with primitives

You may have a headache from debugging your pure lambda calculus code—how do you know what number something is? In this problem, you’ll definie a lambda calculus interpreter that has numbers and booleans, too.

Here’s the new definition of values and expressions. Unfortunately, we can’t reuse the constructor names, so we’ll prefix these values and express with `V` and `E`, respectively.

``````data Value =
VClosure Id Expr (Env Value)
| VNumber Int
| VBoolean Bool

data Expr =
EVar Id
| ETrue
| EFalse
| EIf Expr Expr Expr
| ENum Int
| EIncr Expr
| EDecr Expr
| EIsZero Expr
| EApp Expr Expr
| ELam Id Expr
deriving (Show, Eq)``````

Please define an evaluator for this extended language. If the user does something ‘wrong’—like try to apply a number like a function—then you should use the function `error :: String -> a` to signal an error. Your error message should clearly explain the problem: what type of value did you expect, and what did you get instead? (Soon we’ll define a type system that will rule out these errors entirely.)

``````eval :: Env Value -> Expr -> Value
eval = undefined``````

Write a function `embed`, that embeds the terms of the pure lambda calculus into our new, extended language.

``````embed :: LCExpr -> Expr
embed = undefined``````

Write functions `toChurch` and `fromChurch` in the `Expr` language that convert `ENum` numbers to and from Church numerals. You may want to use the Y combinator (defined below as `y`) to write a recursive function.

``````y :: Expr
y = ELam "f" \$ EApp g g
where g = ELam "x" \$ EApp f (EApp x x)
f = EVar "f"
x = EVar "x"``````

For `toChurch`, you don’t need to worry about negative inputs. (But: given this impoverished language, what would you do if I sadistically required you to worry about them?)

``````toChurch :: Expr
toChurch = undefined``````
``````fromChurch :: Expr
fromChurch = undefined``````

Problem 3: substitution

The semantics for the lambda calculus we’ve used in class uses substitution, not environments. Let’s write an interpreter that uses substitution!

(a) 10 points

What should the type of the substitution function be? How does using substitution change the type of our evaluation function? Do we need to add new datatypes, drop old ones, or leave everything the same? Why or why not?

Think hard about this question before you do parts (b) and (c). Write down your thoughts, and then actually implement the function. Were you right?

fill in here

(b) 5 points

Implement the substitution function for the pure lambda calculus (`LCExpr`). Call it `subst`. You may assume that `e` is closed—there is no need to be capture-avoiding.

(c) 5 points

Implement a call-by-value interpreter for the pure lambda calculus (`LCExpr`) using substitution. Call it `evalSubst`. You can use `error :: String -> a` to signal an error if you need to.

(d) 5 points

What are the pros and cons of the two styles of evaluator we’ve written?

fill in here

(e) 5 points

What do you need to do to adapt your definition of `evalSubst` to use call-by-name evaluation? You may either write code or prose explaining what your code would do.

fill in here