This class explored what programs mean and how languages work, starting from the untyped lambda calculus and ending with a small Haskell-like language with its own interpreter and REPL. Most of the work came as “projects” (graded as assignments), each focused on a different view of computation.


Project 0 – Lambda Calculus

Goal: get comfortable with computation as substitution only.

I:

Example of the style of work:

AND TRUE FALSE
  =a> (\p q -> p q FALSE) TRUE FALSE
  =b> TRUE FALSE FALSE
  =a> (\x y -> x) FALSE FALSE
  =b> FALSE

Project 1 – Tail Recursion & Fixed Points

Focus: tail recursion and turning loops into higher-order functions.

I implemented:

wwhile :: (a -> (Bool, a)) -> a -> a
wwhile f x0 = go x0
  where
    go x = let (cont, x') = f x
           in if cont then go x' else x'

Project 2 – Random Art

We turned an expression language into a picture generator.

Random art samples

I:

data Expr
  = VarX | VarY
  | Sine Expr | Cosine Expr
  | Average Expr Expr
  | Times Expr Expr
  | Thresh Expr Expr Expr Expr
  -- + two extra custom constructors in the assignment

Project 3 – Folds & Big Integers

First part: getting fluent with folds.

sqSum :: [Int] -> Int
sqSum = foldl (\acc x -> acc + x * x) 0

pipe :: [a -> a] -> (a -> a)
pipe fs = foldl (.) id fs

Second part: arbitrary-precision arithmetic using lists:

type BigInt = [Int]  -- e.g. [9,9,9,8] ≡ 9998

I:


Project 4 – Nano: A Mini Haskell

Here we built a small functional language and its interpreter.

Core pieces:

data Expr
  = EInt Int | EBool Bool | ENil | EVar Id
  | EBin Binop Expr Expr
  | EIf Expr Expr Expr
  | ELet Id Expr Expr
  | ELam Id Expr
  | EApp Expr Expr
  deriving Eq

data Value
  = VInt Int | VBool Bool
  | VClos Env Id Expr      -- non-recursive function
  | VRec Id Env Id Expr    -- recursive function
  | VPrim (Value -> Value) -- builtins like head/tail
  | VNil | VCons Value Value

I:


Project 5 – Type Classes, Exceptions & REPL

Final project: combine data structures, monads, and a real interactive shell.

1. Sets via BST + QuickCheck
I implemented a binary search tree and set API:

data BST a = Leaf | Node a (BST a) (BST a)

contains :: Ord a => a -> BST a -> Bool
add      :: Ord a => a -> BST a -> BST a
remove   :: Ord a => a -> BST a -> BST a

Plus:

2. Exceptions with Either
Refactored evaluation to track exceptions explicitly:

evalE :: Env -> Expr -> Either Value Value
eval  :: Env -> Expr -> Value
eval env e = either id id (evalE env e)

I:

3. Nano REPL
Finally, I built a small command-line REPL:

main :: IO ()
main = do
  setLocaleEncoding utf8
  replLoop 0 preludeEnv

Features:

Overall, the projects walked from pure λ-calculus proofs, through Haskell recursion patterns and expression-driven graphics, to a fully working mini language + interpreter + REPL.