## Lambda Calculus in OBJ3

The following OBJ code specifies the lambda calculus in several stages; the code is executable, and a number of examples are given. I only spent a little more than one evening on this, so there may be some bugs in it; please let me know if you find any.
```obj LIST[X :: TRIV] is sort List .
subsort Elt < List .
op nil : -> List .
op __ : List List -> List [assoc id: nil].
op _in_ : Elt List -> Bool .
vars E E' : Elt .  var L : List .
eq E in nil = false .
eq E in E' = E == E' .
eq E in (E' L) = E == E' or E in L .
endo

obj VAR is sorts Lxp Var .
subsort Var < Lxp .
ops a b c d e f g u v w x y z : -> Var .
ops ERROR : -> Lxp .
ops ERROR NOT-VAR-ERROR FREE-ERROR : Var -> Lxp .
pr LIST[Lxp].
op var_ : Lxp -> Bool .
var M : Lxp .
eq var(M) = M in (a b c d e f g u v w x y z).
endo

red var u .
red var ERROR .

obj LAMBDA is pr VAR .
op .\_._ : Var Lxp -> Lxp [prec 2].
op [__] : Lxp Lxp -> Lxp .
*** could have been __, but [__] makes it easier to read expressions
vars X Y Z : Var .  vars L M N : Lxp .

op _free in_  : Var Lxp -> Bool .
eq X free in Y = X == Y .
eq X free in (.\ X . M) = false .
cq X free in (.\ Y . M) = X free in M  if X =/= Y .
eq X free in [M N]      = X free in M or X free in N .

op sub_for_in_ : Lxp Var Lxp -> Lxp .
eq sub L for Y in Y = L .
cq sub L for Y in Z = Z  if Y =/= Z .
cq sub L for Y in (.\ Y . M) = (.\ L .(sub L for Y in M)) if var L .
cq sub L for Y in (.\ Y . M) = NOT-VAR-ERROR(L)  if not var L .
cq sub L for Y in (.\ Z . M) = (.\ Z .(sub L for Y in M)) if Y =/= Z .
eq sub L for Y in [M N]      = [(sub L for Y in M) (sub L for Y in N)] .
endo

red x free in x .
red x free in y .
red x free in (.\ x . .\ y . x).
red x free in (.\ y . .\ x . x).
red x free in (.\ y . .\ z . x).
red x free in [(.\ y . .\ z . z) x].
red x free in [(.\ y . .\ z . y) x].
red x free in [(.\ x . .\ z . x) (.\ x . x)].
red x free in [(.\ x . .\ z . x) (.\ y . x)].
red x free in [(.\ y . [(.\ x . x) y]) (.\ y . x)].

red sub x for y in x .
red sub x for y in y .
red sub x for y in z .
red sub x for y in (.\ x . .\ y . x).
red sub x for y in (.\ z . .\ w . x).
red sub x for y in (.\ z . .\ w . y).
red sub x for y in (.\ z . .\ w . [y z]).
red sub x for y in (.\ z . .\ y . [y z]).

obj ALPHA is pr LAMBDA .
op alpha_for_in_ : Var Var Lxp -> Lxp .
vars-of .
cq alpha Y for X in(.\ X . M) = .\ Y .(sub Y for X in M) if not Y free in M .
cq alpha Y for X in(.\ Z . M) = FREE-ERROR(Y) if Y free in M or X =/= Z .
eq alpha Y for X in Z = ERROR(Y) .
eq alpha Y for X in [M N] = ERROR .
endo

***> test alpha reduction:
red alpha y for x in x .                 *** should be ERROR
red alpha y for x in (.\ x . x ).
red alpha y for x in (.\ x . .\ y . x).  *** maybe should be ERROR (but isnt)
red alpha y for x in (.\ x . .\ z . x).
red alpha y for x in (.\ y . .\ x . y).  *** should be ERROR
red alpha y for x in (.\ y . .\ x . x).  *** should be ERROR
red alpha y for x in (.\ y . .\ x . z).  *** should be ERROR
red alpha y for x in [(.\ x . x) c].     *** should be ERROR

obj BETA is pr ALPHA .
vars-of .
cq [(.\ X . M) N] = sub N for X in M if not X free in N .
cq [(.\ X . X) N] = FREE-ERROR(X) if X free in N .
endo

***> test beta reduction:
red [(.\ x . x) c].
red [(.\ x . y) c].
red [(.\ y .(.\ z .[z y])) c].
red [[(.\ y .(.\ z .[z y])) c] (.\ x . x)] .
red [[(.\ x .(.\ y .[x y])) (.\ z . x)] c].
red [[(.\ x .(.\ y . x)) c] [(.\ z . [f z]) b]].
red [[(.\ x .(.\ y .[x y])) (.\ z . z)] c].
red [(.\ y .(.\ z .[z y])) (.\ z . [z z])].
red [(.\ y .(.\ z .[z y])) (.\ z . [y z])].
red [[(.\ x .(.\ y .(.\ x .[x [x y]]))) (.\ z . [[f x] z])] [g x]].
red [[(.\ x .(.\ y .[x y])) (.\ z . y)] c].

openr .
let I  = (.\ x . x).
let K  = (.\ u .(.\ v . u)).
let S  = (.\ x .(.\ y .(.\ z . [[x z][y z]]))).
let XX = (.\ x .[x x]).
close

red [K z].
red [[[S K] K] w] == [I w].
red [[[S K] K] w].
red [[S K] K] == I .
red [[S K] K] .
***> red [XX XX].  *** fails to terminate!
***> yields "Error: Value stack overflow."

obj BETA-ETA is pr BETA .
vars-of .
cq [(.\ X . M) X] = M if not X free in M .
endo

red [K z].
red [[[S K] K] w] == [I w].
red [[[S K] K] w].
red [[S K] K] == I .
red [[S K] K] .
***> red [XX XX].  *** fails to terminate!

obj ARITH is pr BETA .
vars-of .
let T = (.\ x . .\ y . x).
let F = (.\ x . .\ y . y).
op IF[_,_,_] : Lxp Lxp Lxp -> Lxp .
op Pair[_,_] : Lxp Lxp -> Lxp .
ops (First[_]) (Rest[_]) : Lxp -> Lxp .
op Zero : -> Lxp .
ops (Succ[_]) (IsZero[_]) (Pred[_]) : Lxp -> Lxp .

eq IF[L,M,N] = [[L M] N].
eq Pair[L,M] = (.\ u . IF[u,L,M]). *** wont work with x instead of u
eq First[M]  = [M T].
eq Rest[M]   = [M F].
eq Zero      = (.\ v . v).
eq Succ[M]   = Pair[F,M].
eq IsZero[M] = First[M].
eq Pred[M]   = Rest[M].
endo

red IF[T,a,b].
red IF[F,a,b].
red First[Pair[a,b]].
red Rest[Pair[a,b]].
red IsZero[Zero] == T .
red IsZero[Zero].
red IsZero[Succ[Zero]] == T .
red IsZero[Succ[Zero]].  ***> this needs an alpha reduction
red Pred[Succ[Zero]] == Zero .
red Pred[Succ[Zero]].
```