lambda/
lambda.rs

1//! Example: Untyped lambda calculus with the unbound library
2
3use unbound::prelude::*;
4
5// Variables are names that stand for expressions
6type Var = Name<Expr>;
7
8// Lambda calculus expressions
9#[derive(Clone, Debug, Alpha, Subst)]
10enum Expr {
11    V(Var),                    // Variables
12    Lam(Bind<Var, Box<Expr>>), // Lambda abstractions
13    App(Box<Expr>, Box<Expr>), // Applications
14}
15
16impl Expr {
17    fn var(name: Var) -> Expr {
18        Expr::V(name)
19    }
20
21    fn lam(var: Var, body: Expr) -> Expr {
22        Expr::Lam(bind(var, Box::new(body)))
23    }
24
25    fn app(e1: Expr, e2: Expr) -> Expr {
26        Expr::App(Box::new(e1), Box::new(e2))
27    }
28}
29
30impl std::fmt::Display for Expr {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        match self {
33            Expr::V(x) => write!(f, "{}", x),
34            Expr::Lam(bnd) => write!(f, "λ{}", bnd),
35            Expr::App(e1, e2) => write!(f, "({} {})", e1, e2),
36        }
37    }
38}
39
40// Evaluate to normal form
41fn eval(expr: Expr) -> FreshM<Expr> {
42    match expr {
43        Expr::V(x) => FreshM::pure(Expr::V(x)),
44        Expr::Lam(bnd) => {
45            let (x, body) = bnd.unbind();
46            eval(*body).map(move |evaluated_body| Expr::Lam(bind(x, Box::new(evaluated_body))))
47        }
48        Expr::App(e1, e2) => eval(*e1.clone()).and_then(move |v1| {
49            eval(*e2.clone()).and_then(move |v2| match v1 {
50                Expr::Lam(bnd) => {
51                    let (x, body) = bnd.unbind();
52                    let substituted = body.subst(&x, &v2);
53                    eval(*substituted)
54                }
55                other => FreshM::pure(Expr::app(other, v2)),
56            })
57        }),
58    }
59}
60
61fn main() {
62    println!("=== Unbound Lambda Calculus Demo ===\n");
63
64    // 1. Alpha equivalence
65    println!("1. Alpha Equivalence");
66    println!("--------------------");
67    let x = s2n("x");
68    let y = s2n("y");
69    let id_x = Expr::lam(x.clone(), Expr::var(x));
70    let id_y = Expr::lam(y.clone(), Expr::var(y));
71
72    println!("λx.x = {}", id_x);
73    println!("λy.y = {}", id_y);
74    println!("Are they alpha-equivalent? {}\n", id_x.aeq(&id_y));
75
76    // 2. Substitution
77    println!("2. Capture-Avoiding Substitution");
78    println!("---------------------------------");
79    let z = s2n("z");
80    let expr = Expr::app(id_x.clone(), Expr::var(z.clone()));
81
82    println!("Expression: (λx.x) z = {}", expr);
83    let result = run_fresh(eval(expr));
84    println!("After evaluation: {}\n", result);
85
86    // 3. Church Booleans
87    println!("3. Church Booleans");
88    println!("------------------");
89    let t = s2n::<Expr>("t");
90    let f = s2n::<Expr>("f");
91
92    let true_church = Expr::lam(t.clone(), Expr::lam(f.clone(), Expr::var(t.clone())));
93    let false_church = Expr::lam(t.clone(), Expr::lam(f.clone(), Expr::var(f.clone())));
94
95    println!("TRUE  = λt.λf.t = {}", true_church);
96    println!("FALSE = λt.λf.f = {}", false_church);
97    println!(
98        "Are they alpha-equivalent? {}\n",
99        true_church.aeq(&false_church)
100    );
101
102    // 4. Church Numerals
103    println!("4. Church Numerals");
104    println!("------------------");
105    let f = s2n::<Expr>("f");
106    let x = s2n::<Expr>("x");
107
108    let zero = Expr::lam(f.clone(), Expr::lam(x.clone(), Expr::var(x.clone())));
109    let one = Expr::lam(
110        f.clone(),
111        Expr::lam(
112            x.clone(),
113            Expr::app(Expr::var(f.clone()), Expr::var(x.clone())),
114        ),
115    );
116    let two = Expr::lam(
117        f.clone(),
118        Expr::lam(
119            x.clone(),
120            Expr::app(
121                Expr::var(f.clone()),
122                Expr::app(Expr::var(f.clone()), Expr::var(x)),
123            ),
124        ),
125    );
126
127    println!("ZERO = λf.λx.x     = {}", zero);
128    println!("ONE  = λf.λx.f x   = {}", one);
129    println!("TWO  = λf.λx.f(f x) = {}", two);
130    println!("Is ZERO ≡ ONE? {}", zero.aeq(&one));
131    println!("Is ZERO ≡ TWO? {}", zero.aeq(&two));
132    println!("Is ONE ≡ TWO? {}\n", one.aeq(&two));
133
134    // 5. Combinator Calculus
135    println!("5. Combinators");
136    println!("--------------");
137
138    // S combinator: λf.λg.λx.f x (g x)
139    let f = s2n::<Expr>("f");
140    let g = s2n::<Expr>("g");
141    let x = s2n::<Expr>("x");
142
143    let s_combinator = Expr::lam(
144        f.clone(),
145        Expr::lam(
146            g.clone(),
147            Expr::lam(
148                x.clone(),
149                Expr::app(
150                    Expr::app(Expr::var(f.clone()), Expr::var(x.clone())),
151                    Expr::app(Expr::var(g), Expr::var(x.clone())),
152                ),
153            ),
154        ),
155    );
156
157    // K combinator: λx.λy.x
158    let k_x = s2n::<Expr>("x");
159    let k_y = s2n::<Expr>("y");
160    let k_combinator = Expr::lam(k_x.clone(), Expr::lam(k_y, Expr::var(k_x)));
161
162    // I combinator can be derived from S and K: S K K
163    let i_derived = Expr::app(
164        Expr::app(s_combinator.clone(), k_combinator.clone()),
165        k_combinator.clone(),
166    );
167
168    println!("S = λf.λg.λx.f x (g x) = {}", s_combinator);
169    println!("K = λx.λy.x = {}", k_combinator);
170    println!("I = S K K = {}", i_derived);
171
172    // Test that S K K behaves like identity
173    let test = s2n::<Expr>("test");
174    let test_app = Expr::app(i_derived, Expr::var(test.clone()));
175    let result = run_fresh(eval(test_app));
176    println!("(S K K) test = {}", result);
177
178    match result {
179        Expr::V(v) if v == test => println!("✓ S K K behaves like identity!"),
180        _ => println!("✗ S K K does not behave like identity"),
181    }
182}