Skip to content

Instantly share code, notes, and snippets.

@siraben
Last active August 20, 2020 17:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save siraben/5209bfc7165c45aec18eeae852ec7d62 to your computer and use it in GitHub Desktop.
Save siraben/5209bfc7165c45aec18eeae852ec7d62 to your computer and use it in GitHub Desktop.
Lambda calculus interpreter in Rust
use std::rc::Rc;
// Environment-passing lambda calculus interpreter in Rust
#[derive(Debug, Clone, PartialEq)]
enum LC {
Var(String),
App(Box<LC>, Box<LC>),
Abs(String, Box<LC>),
Lit(u32),
Incr(Box<LC>),
}
#[derive(Debug, Clone, PartialEq)]
enum Env {
EmptyEnv,
ExtEnv((String, Val), Rc<Env>),
}
#[derive(Debug, Clone, PartialEq)]
enum Val {
IntTag(u32),
ClosTag(Rc<Env>, String, LC),
}
use Env::*;
use Val::*;
use LC::*;
// Lookup a value in an environment
fn lookup<'a>(var: &String, e: &'a Env) -> Option<&'a Val> {
match e {
EmptyEnv => None,
ExtEnv((s, val), rest) => {
if s == var {
Some(val)
} else {
lookup(var, &*rest)
}
}
}
}
// Evaluate a lambda term
fn eval(lc: LC, e: Rc<Env>) -> Option<Val> {
match lc {
Var(s) => match lookup(&s, &*e) {
Some(val) => Some((*val).clone()),
_ => None,
},
App(f, x) => match eval(*x, e.clone()) {
Some(val) => match eval(*f, e) {
Some(ClosTag(env2, v, b)) => eval(b, Rc::new(ExtEnv((v, val), env2.clone()))),
_ => None,
},
_ => None,
},
Abs(v, b) => Some(ClosTag(e, v, *b)),
Lit(i) => Some(IntTag(i)),
Incr(b) => match eval(*b, e) {
Some(IntTag(i)) => Some(IntTag(i + 1)),
_ => None,
},
}
}
// Evaluate (\x -> x) 5 in empty environment
#[test]
fn eval_test1() {
assert_eq!(
eval(
App(
Box::new(Abs(
String::from("x"),
Box::new(Incr(Box::new(Var(String::from("x")))))
)),
Box::new(Lit(5))
),
Rc::new(EmptyEnv)
),
Some(IntTag(6))
)
}
// Evaluate (\x -> incr x) y in environment where y is bound to 10
#[test]
fn eval_test2() {
assert_eq!(
eval(
App(
Box::new(Abs(
String::from("x"),
Box::new(Incr(Box::new(Var(String::from("x")))))
)),
Box::new(Var(String::from("y")))
),
Rc::new(ExtEnv((String::from("y"), IntTag(10)), Rc::new(EmptyEnv)))
),
Some(IntTag(11))
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment