Lambda Calculus in Haskell
Some boilerplate:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DataKinds #-}
module Main where
import Prelude hiding (map)
import Data.SetOur 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 + 1freeVars :: 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 = xA 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')))