gdritter repos rust-examples / 82429f0
Updated lcalc to Rust stable Getty Ritter 9 years ago
1 changed file(s) with 39 addition(s) and 33 deletion(s). Collapse all Expand all
1 use std::thread;
2
13 // This isn't a very Rust-ey lambda-calculus implementation. It's much
24 // more TAPL-ey, which I think makes it nice for pedagogical purposes
35 // when aimed at functional programmers, but you wouldn't actually
46 // use Rust like this in practice.
57
6 #[deriving(Eq,PartialEq,Clone,Show)]
8 #[derive(Eq,PartialEq,Clone,Debug)]
79 enum Term {
8 Num(int),
10 Num(i32),
911 Var(String),
1012 Lam(String, Box<Term>),
1113 App(Box<Term>, Box<Term>),
1416
1517 // The following are wrappers over λ-terms to simplify writing
1618 // allocations. It really does help, as you can see in main.
17 fn num(n: int) -> Box<Term> {
18 box Term::Num(n)
19 fn num(n: i32) -> Box<Term> {
20 Box::new(Term::Num(n))
1921 }
2022
2123 fn var(s: &str) -> Box<Term> {
22 box Term::Var(s.to_string())
24 Box::new(Term::Var(s.to_string()))
2325 }
2426
2527 fn lam(x: &str, n: Box<Term>) -> Box<Term> {
26 box Term::Lam(x.to_string(), n)
28 Box::new(Term::Lam(x.to_string(), n))
2729 }
2830
2931 fn app(x: Box<Term>, y: Box<Term>) -> Box<Term> {
30 box Term::App(x, y)
32 Box::new(Term::App(x, y))
3133 }
3234
3335 fn let_(x: &str, y: Box<Term>, z: Box<Term>) -> Box<Term> {
34 box Term::Let(x.to_string(), y, z)
36 Box::new(Term::Let(x.to_string(), y, z))
3537 }
3638
3739 // A value is either a number or a closure, which has to have
3840 // its environment around. We'll have to clone the environment
3941 // into the closure to make sure that it stays around even if
4042 // the closure is returned from the environment where it was used.
41 #[deriving(Eq,PartialEq,Clone,Show)]
43 #[derive(Eq,PartialEq,Clone,Debug)]
4244 enum Val {
43 Num(int),
45 Num(i32),
4446 Lam(String, Box<Term>, Box<Env>),
47 }
48
49 fn vnum(n: i32) -> Box<Val> {
50 Box::new(Val::Num(n))
51 }
52
53 fn vlam(x: String, b: Box<Term>, e: Box<Env>) -> Box<Val> {
54 Box::new(Val::Lam(x, b, e))
4555 }
4656
4757 // I could also use a pair of a map and a parent pointer, but
4858 // this is a little more TAPL-ish. Plus, we generally always
4959 // bind a single variable at a time.
50 #[deriving(Eq,PartialEq,Clone,Show)]
60 #[derive(Eq,PartialEq,Clone,Debug)]
5161 enum Env {
5262 Empty,
5363 Binding(String, Box<Val>, Box<Env>),
7383 // ownership.
7484 fn lcalc_eval(t: &Term, e: &Env) -> Box<Val> {
7585 match t {
76 &Term::Num(num) => {
77 box Val::Num(num)
86 &Term::Num(num) => vnum(num),
87 &Term::Var(ref str) => lookup(str, e),
88 &Term::Lam(ref s, ref b) => {
89 vlam(s.clone(), b.clone(), Box::new(e.clone()))
7890 }
79 &Term::Var(ref str) => {
80 lookup(str, e)
81 }
82 &Term::Lam(ref s, ref b) => {
83 box Val::Lam(s.clone(), b.clone(), box e.clone())
84 }
85 &Term::App(box ref f, box ref x) => {
91 &Term::App(ref f, ref x) => {
8692 match *lcalc_eval(f, e) {
87 Val::Lam(ref arg, box ref body, box ref env) => {
88 let new_env = Env::Binding(arg.clone(),
89 lcalc_eval(x, e),
90 box env.clone());
93 Val::Lam(ref arg, ref body, ref env) => {
94 let new_env = Env::Binding(arg.clone(),
95 lcalc_eval(x, e),
96 Box::new(*env.clone()));
9197 lcalc_eval(body, &new_env)
9298 }
9399 _ => panic!("Tried to apply a non-function!")
94100 }
95101 }
96 &Term::Let(ref s, box ref t, box ref b) => {
102 &Term::Let(ref s, ref t, ref b) => {
97103 let new_env =
98 Env::Binding(s.clone(),
99 lcalc_eval(t, e),
100 box e.clone());
104 Env::Binding(s.clone(),
105 lcalc_eval(t, e),
106 Box::new(e.clone()));
101107 lcalc_eval(b, &new_env)
102108 }
103109 }
108114 fn lcalc_eval_opt(t: &Term, e: &Env) -> Option<Box<Val>> {
109115 let new_term = t.clone();
110116 let new_env = e.clone();
111 let guard = std::thread::Thread::spawn(move || {
117 let guard = thread::spawn(move || {
112118 lcalc_eval(&new_term, &new_env)
113119 });
114120 match guard.join() {
133139 // (2)(3), which will also obviously fail
134140 let s4 = app(num(2), num(3));
135141 let e = Env::Empty;
136 println!("s1: {:}", lcalc_eval_opt(&*s1, &e));
137 println!("s2: {:}", lcalc_eval_opt(&*s2, &e));
138 println!("s3: {:}", lcalc_eval_opt(&*s3, &e));
139 println!("s4: {:}", lcalc_eval_opt(&*s4, &e));
142 println!("s1: {:?}", lcalc_eval_opt(&*s1, &e));
143 println!("s2: {:?}", lcalc_eval_opt(&*s2, &e));
144 println!("s3: {:?}", lcalc_eval_opt(&*s3, &e));
145 println!("s4: {:?}", lcalc_eval_opt(&*s4, &e));
140146 }