/
lc.rs
92 lines (80 loc) · 2.4 KB
/
lc.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//! An example of using the `moniker` library to implement the untyped lambda
//! calculus
#[macro_use]
extern crate moniker;
use moniker::{Binder, Scope, Var};
use std::rc::Rc;
/// Expressions
///
/// ```text
/// e ::= x variables
/// | \x => e anonymous functions
/// | e₁ e₂ function application
/// ````
#[derive(Debug, Clone, BoundTerm)]
pub enum Expr {
/// Variables
Var(Var<String>),
/// Lambda expressions
Lam(Scope<Binder<String>, RcExpr>),
/// Function application
App(RcExpr, RcExpr),
}
/// Reference counted expressions
#[derive(Debug, Clone, BoundTerm)]
pub struct RcExpr {
pub inner: Rc<Expr>,
}
impl From<Expr> for RcExpr {
fn from(src: Expr) -> RcExpr {
RcExpr {
inner: Rc::new(src),
}
}
}
impl RcExpr {
// FIXME: auto-derive this somehow!
fn subst<N: PartialEq<Var<String>>>(&self, name: &N, replacement: &RcExpr) -> RcExpr {
match *self.inner {
Expr::Var(ref var) if name == var => replacement.clone(),
Expr::Var(_) => self.clone(),
Expr::Lam(ref scope) => RcExpr::from(Expr::Lam(Scope {
unsafe_pattern: scope.unsafe_pattern.clone(),
unsafe_body: scope.unsafe_body.subst(name, replacement),
})),
Expr::App(ref fun, ref arg) => RcExpr::from(Expr::App(
fun.subst(name, replacement),
arg.subst(name, replacement),
)),
}
}
}
/// Evaluate an expression into its normal form
pub fn eval(expr: &RcExpr) -> RcExpr {
match *expr.inner {
Expr::Var(_) | Expr::Lam(_) => expr.clone(),
Expr::App(ref fun, ref arg) => match *eval(fun).inner {
Expr::Lam(ref scope) => {
let (binder, body) = scope.clone().unbind();
eval(&body.subst(&binder, &eval(arg)))
},
_ => expr.clone(),
},
}
}
#[test]
fn test_eval() {
use moniker::FreeVar;
let x = FreeVar::fresh_named("x");
let y = FreeVar::fresh_named("y");
// expr = (\x -> x) y
let expr = RcExpr::from(Expr::App(
RcExpr::from(Expr::Lam(Scope::new(
Binder(x.clone()),
RcExpr::from(Expr::Var(Var::Free(x.clone()))),
))),
RcExpr::from(Expr::Var(Var::Free(y.clone()))),
));
assert_term_eq!(eval(&expr), RcExpr::from(Expr::Var(Var::Free(y.clone()))));
}
fn main() {}