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
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 }