1use unbound::prelude::*;
4
5type Var = Name<Expr>;
7
8#[derive(Clone, Debug, Alpha, Subst)]
10enum Expr {
11 V(Var), Lam(Bind<Var, Box<Expr>>), App(Box<Expr>, Box<Expr>), }
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
40fn 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 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 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 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 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 println!("5. Combinators");
136 println!("--------------");
137
138 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 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 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 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}