bind

Function bind 

Source
pub fn bind<P, T>(pattern: P, body: T) -> Bind<P, T>
Expand description

Helper function to bind a pattern in a body

Examples found in repository?
examples/lambda.rs (line 22)
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}
More examples
Hide additional examples
examples/system_f.rs (line 81)
80    fn forall(vars: Vec<TyName>, ty: Ty) -> Ty {
81        Ty::All(bind(vars, Box::new(ty)))
82    }
83}
84
85impl fmt::Display for Ty {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        match self {
88            Ty::TyVar(a) => write!(f, "{}", a),
89            Ty::Arr(t1, t2) => write!(f, "({} → {})", t1, t2),
90            Ty::All(bnd) => {
91                let vars = bnd.pattern();
92                write!(f, "∀")?;
93                for (i, v) in vars.iter().enumerate() {
94                    if i > 0 {
95                        write!(f, " ")?;
96                    }
97                    write!(f, "{}", v)?;
98                }
99                write!(f, ". {}", bnd.body())
100            }
101        }
102    }
103}
104
105/// Embedded type annotation
106#[derive(Clone, Debug, PartialEq)]
107struct Embed<T>(T);
108
109impl<T: Alpha> Alpha for Embed<T> {
110    fn aeq(&self, other: &Self) -> bool {
111        self.0.aeq(&other.0)
112    }
113
114    fn aeq_in(&self, ctx: &mut AlphaCtx, other: &Self) -> bool {
115        self.0.aeq_in(ctx, &other.0)
116    }
117
118    fn fv_in(&self, vars: &mut Vec<String>) {
119        self.0.fv_in(vars)
120    }
121}
122
123impl<T: Subst<V>, V> Subst<V> for Embed<T> {
124    fn is_var(&self) -> Option<SubstName<V>> {
125        None
126    }
127
128    fn subst(&self, var: &Name<V>, value: &V) -> Self {
129        Embed(self.0.subst(var, value))
130    }
131}
132
133/// System F terms
134#[derive(Clone, Debug, Alpha)]
135#[allow(dead_code)]
136enum Tm {
137    /// Term variables
138    TmVar(TmName),
139    /// Term abstraction (lambda)
140    Lam(Bind<(TmName, Embed<Ty>), Box<Tm>>),
141    /// Type abstraction (big lambda)
142    TLam(Bind<Vec<TyName>, Box<Tm>>),
143    /// Term application
144    App(Box<Tm>, Box<Tm>),
145    /// Type application
146    TApp(Box<Tm>, Vec<Ty>),
147}
148
149// Only need to specify when it's a variable for Subst<Tm>
150impl Subst<Tm> for Tm {
151    fn is_var(&self) -> Option<SubstName<Tm>> {
152        match self {
153            Tm::TmVar(v) => Some(SubstName::Name(v.clone())),
154            _ => None,
155        }
156    }
157
158    fn subst(&self, var: &Name<Tm>, value: &Tm) -> Self {
159        match self {
160            Tm::TmVar(v) if v == var => value.clone(),
161            Tm::TmVar(v) => Tm::TmVar(v.clone()),
162            Tm::Lam(b) => {
163                let (x, ann) = b.pattern();
164                if x == var {
165                    // Variable is bound, no substitution
166                    self.clone()
167                } else {
168                    // Substitute in body
169                    Tm::Lam(Bind::new(
170                        (x.clone(), ann.clone()),
171                        Box::new((**b.body()).subst(var, value)),
172                    ))
173                }
174            }
175            Tm::TLam(b) => {
176                // Type variables can't capture term variables, so substitute in body
177                Tm::TLam(Bind::new(
178                    b.pattern().clone(),
179                    Box::new((**b.body()).subst(var, value)),
180                ))
181            }
182            Tm::App(e1, e2) => Tm::App(
183                Box::new((**e1).subst(var, value)),
184                Box::new((**e2).subst(var, value)),
185            ),
186            Tm::TApp(t, tys) => Tm::TApp(Box::new((**t).subst(var, value)), tys.clone()),
187        }
188    }
189}
190
191// Subst Ty Tm - substituting types in terms
192impl Subst<Ty> for Tm {
193    fn is_var(&self) -> Option<SubstName<Ty>> {
194        None // Terms never contain type variables at the term level
195    }
196
197    fn subst(&self, var: &Name<Ty>, value: &Ty) -> Self {
198        match self {
199            Tm::TmVar(x) => Tm::TmVar(x.clone()),
200            Tm::Lam(b) => {
201                let (x, Embed(ty)) = b.pattern();
202                Tm::Lam(Bind::new(
203                    (x.clone(), Embed(ty.subst(var, value))),
204                    Box::new((**b.body()).subst(var, value)),
205                ))
206            }
207            Tm::TLam(b) => {
208                let vars = b.pattern();
209                if vars.iter().any(|v| v == var) {
210                    // Type variable is bound, no substitution
211                    self.clone()
212                } else {
213                    Tm::TLam(Bind::new(
214                        vars.clone(),
215                        Box::new((**b.body()).subst(var, value)),
216                    ))
217                }
218            }
219            Tm::App(e1, e2) => Tm::App(
220                Box::new((**e1).subst(var, value)),
221                Box::new((**e2).subst(var, value)),
222            ),
223            Tm::TApp(t, tys) => Tm::TApp(
224                Box::new((**t).subst(var, value)),
225                tys.iter().map(|ty| ty.subst(var, value)).collect(),
226            ),
227        }
228    }
229}
230
231impl Tm {
232    fn var(name: TmName) -> Tm {
233        Tm::TmVar(name)
234    }
235
236    fn lam(var: TmName, ty: Ty, body: Tm) -> Tm {
237        Tm::Lam(bind((var, Embed(ty)), Box::new(body)))
238    }
239
240    fn tlam(tyvars: Vec<TyName>, body: Tm) -> Tm {
241        Tm::TLam(bind(tyvars, Box::new(body)))
242    }