1use crate::exp::{Exp, Ident};
3
4impl<T: Clone + Eq> Exp<T> {
5 fn bind(&mut self, id: &T, de_bruijn_index: u32) -> &mut Self {
9 match self {
10 Exp::Var(var) => {
11 if var.0 == *id {
12 var.1 = de_bruijn_index
13 }
14 }
15 Exp::Abs(var, exp) => {
16 if var.0 != *id {
17 exp.bind(id, de_bruijn_index + 1);
18 }
19 }
20 Exp::App(l, exp) => {
21 l.bind(id, de_bruijn_index);
22 exp.bind(id, de_bruijn_index);
23 }
24 };
25 self
26 }
27}
28
29#[doc(hidden)]
30pub fn app<T>(exps: Vec<Exp<T>>) -> Exp<T>
31where
32 T: Clone + Eq,
33{
34 let mut res = None;
35 for exp in exps {
36 res = match res {
37 Some(l) => Some(Exp::App(Box::new(l), Box::new(exp))),
38 None => Some(exp),
39 }
40 }
41 res.unwrap()
42}
43
44#[doc(hidden)]
45pub fn abs<T>(v: T, exp: Exp<T>) -> Exp<T>
46where
47 T: Clone + Eq,
48{
49 let mut exp = exp;
50 exp.bind(&v, 1); Exp::Abs(Ident(v, 0), Box::new(exp))
52}
53
54#[doc(hidden)]
55pub fn unbounded_var<T>(v: T) -> Exp<T>
56where
57 T: Clone + Eq,
58{
59 Exp::Var(Ident(v, 0))
60}
61
62#[macro_export]
73macro_rules! lambda {
74 [($( $t:tt )+)] => {
76 lambda![$( $t )+]
77 };
78 [{$v:expr}] => {
80 $v.clone()
81 };
82 [$v:ident] => {
85 $crate::builder::unbounded_var::<String>(String::from(stringify!($v)))
86 };
87 [$v:ident.$( $t:tt )+] => {
89 $crate::builder::abs(String::from(stringify!($v)), lambda![$( $t )+])
90 };
91 [$l:tt $( $t:tt )+] => {
93 $crate::builder::app(vec![lambda![$l], $( lambda![$t] ),+])
94 };
95}
96
97#[cfg(test)]
98mod tests {
99 use crate::builder::{abs, app, unbounded_var};
100
101 #[test]
102 fn test_builder() {
103 let and = lambda!(x. (y. x y x));
104 assert_eq!(
105 and,
106 abs(
107 String::from("x"),
108 abs(
109 String::from("y"),
110 app(vec![
111 unbounded_var(String::from("x")),
112 unbounded_var(String::from("y")),
113 unbounded_var(String::from("x")),
114 ])
115 )
116 )
117 );
118 }
119}