Lambda Calculus in Haskell

Some boilerplate:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DataKinds #-}
module Main where

import Prelude hiding (map)
import Data.Set

Our Representation of the Lambda Calculus:

data Syntax = Var Char | Abs Char Syntax | Ap Syntax Syntax
  deriving (Show,Eq,Ord)

Syntax: this type represents an arbitrary program in Lambda Calculus. Var represents a leaf of the AST, a variable that may either be bound or unbound. Abs represents one-argument function definition. Ap represents the application of a function to some arbitrary program.

Some functions for extracting interesting facts from a program:

sLength: function, determines the length of an expression.

freeVars: get the set of free variables in an expression.

boundVars: get the set of bound variables in an expression.

sub: what does this do?

sLength :: Syntax -> Integer
sLength (Var x) = 1
sLength (Ap a b) = sLength a + sLength b + 1
sLength (Abs _ s) = sLength s + 1

freeVars :: Set Char -> Syntax -> Set Char
freeVars vars (Var char) = insert char vars
freeVars vars (Ap exp arg) = union (union (freeVars vars exp) (freeVars vars arg)) vars
freeVars vars (Abs arg body) = union vars (delete arg $ freeVars vars body)

boundVars vars (Var x) = vars
boundVars vars (Ap a b) = union (boundVars vars a) (boundVars vars b)
boundVars vars (Abs a s) = insert a (boundVars vars s)

sub terms t@(Var _) = fromList [t]
sub terms t@(Abs x body) = sub (insert t terms) body
sub terms t@(Ap l r) = insert t $ union (sub terms l) (sub terms r)

Functions for generically finding the occurence of a variable:

The PathTok datatype represents one step in the process of descending down a program until you reach a specified variable. [PathTok] represents the path to one specific variable.

The path function takes a Syntax element and constructs a set of all the possible paths in a given expression contains.

The occ function takes an expression and a path and either returns the variable specified by the path, if such exists.

data PathTok = R | L | Star
  deriving (Ord,Show,Eq)
path :: Syntax -> Set [PathTok]
path (Var x) = fromList [[]]
path (Abs x s) = union (fromList [[]]) (map (\x -> Star:x) $ path s)
path (Ap t r) = insert [] $
  union (map (\x -> L:x) $ path t)
        (map (\x -> R:x) $ path r)
occ :: Syntax -> [PathTok] -> Maybe Syntax
occ (Var t) [] = Just t
occ (Ap t r) (L:tail) = occ t tail >>= Just
occ (Ap t r) (R:tail) = occ r tail >>= Just
occ (Abs x s) (Star:tail) = occ s tail >>= Just
occ _ _ = Nothing

expand :: Char -> Syntax -> Syntax -> Syntax
expand var val (Ap exp arg) = Ap (expand var val exp) (expand var val arg)
expand var val (Abs arg body) | var /= arg = Abs arg (expand var val body)
expand var val (Abs arg body) | var == arg = undefined
expand var val (Var body) | var == body = val
expand var val body = body

Beta Reduction (incomplete):

betaReduce :: Syntax -> Syntax
betaReduce (Ap (Abs var body) val) = expand var val body
betaReduce x = x

A couple (very useful) programs expressed in our Lambda Calculus:

yComb :: Syntax
yComb = Abs 'f' (Ap (Abs 'x' (Ap (Var 'f') (Ap (Var 'x') (Var 'x'))))
                    (Abs 'x' (Ap (Var 'f') (Ap (Var 'x') (Var 'x')))))
succ'  = Abs 'n' $ Abs 'f' $ Abs 'x' $ Ap (Var 'f') (Ap (Var 'n') (Ap (Var 'f') (Var 'x')))
succ'' = Abs 'm' $ Abs 'g' $ Abs 'c' $ Ap (Var 'g') (Ap (Var 'm') (Ap (Var 'g') (Var 'c')))