+#[derive(Clone, Debug)]
+enum Term {
+ Var(usize),
+ Lam(Box<Term>),
+ App(Box<(Term, Term)>),
+ Nil,
+ MkPair(Box<(Term, Term)>),
+ Car(Box<Term>),
+ Cdr(Box<Term>),
+ Lit(usize),
+}
+
+impl Term {
+ fn eval(&self) -> Value {
+ run(self.compile(), Value::Null, vec![])
+ }
+
+ fn compile(&self) -> Vec<Instruction> {
+ match self {
+ Term::Var(0) => vec![Instruction::Snd],
+ Term::Var(n) => {
+ let mut res = vec![Instruction::Fst];
+ res.append(&mut Term::Var(n - 1).compile());
+ res
+ },
+ Term::Lam(t) => vec![Instruction::Cur(t.compile())],
+ Term::App(tuple) => {
+ let (t0, t1) = *tuple.clone();
+ let mut result = vec![Instruction::Push];
+
+ result.append(&mut t0.compile());
+ result.push(Instruction::Swap);
+ result.append(&mut t1.compile());
+ result.push(Instruction::Cons);
+ result.push(Instruction::Call);
+
+ result
+ },
+ Term::Nil => vec![Instruction::Quote(Value::Null)],
+ Term::MkPair(tuple) => {
+ let (t0, t1) = *tuple.clone();
+ let mut result = vec![Instruction::Push];
+
+ result.append(&mut t0.compile());
+ result.push(Instruction::Swap);
+ result.append(&mut t1.compile());
+ result.push(Instruction::Cons);
+
+ result
+ },
+ Term::Car(t) => {
+ let mut result = t.compile();
+ result.push(Instruction::Fst);
+ result
+ },
+ Term::Cdr(t) => {
+ let mut result = t.compile();
+ result.push(Instruction::Snd);
+ result
+ },
+ Term::Lit(n) => vec![Instruction::Quote(Value::Num(*n))],
+ _ => todo!(),
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+enum Instruction {
+ Fst,
+ Snd,
+ Push,
+ Swap,
+ Cons,
+ Call,
+ Cur(Vec<Instruction>),
+ Quote(Value),
+}
+
+#[derive(Clone, Debug)]
+enum Value {
+ Null,
+ Pair(Box<(Value, Value)>),
+ Closure(Box<Value>, Vec<Instruction>),
+ Num(usize),
+}
+
+type Stack = Vec<Value>;
+
+fn run(instrs: Vec<Instruction>, v: Value, s: Stack) -> Value {
+
+ match (instrs.split_first(), v.clone(), s.split_first()) {
+ (Some((Instruction::Fst, tail)), Value::Pair(tuple), _) => {
+ let (v1, _) = *tuple.clone();
+ run(tail.to_vec(), v1, s)
+ },
+ (Some((Instruction::Snd, tail)), Value::Pair(tuple), _) => {
+ let (_, v2) = *tuple.clone();
+ run(tail.to_vec(), v2, s)
+ },
+ (Some((Instruction::Quote(val), tail)), _, _) => {
+ run(tail.to_vec(), val.clone(), s)
+ },
+ (Some((Instruction::Cur(steps), tail)), _, _) => {
+ run(tail.to_vec(), Value::Closure(Box::new(v), steps.to_vec()), s)
+ },
+ (Some((Instruction::Push, tail)), _, _) => {
+ let mut new_stack = vec![v.clone()];
+ new_stack.append(&mut s.clone());
+ run(tail.to_vec(), v, new_stack)
+ },
+ (Some((Instruction::Swap, tail)), _, Some((val, s_tail))) => {
+ let mut new_stack = vec![v.clone()];
+ new_stack.append(&mut s_tail.to_vec());
+ run(tail.to_vec(), val.clone(), new_stack)
+ },
+ (Some((Instruction::Cons, tail)), _, Some((val, s_tail))) => {
+ run(tail.to_vec(), Value::Pair(Box::new((val.clone(), v))), s_tail.to_vec())
+ },
+ (Some((Instruction::Call, tail)), Value::Pair(tuple), _) => {
+ let (Value::Closure(v0, steps), v1) = *tuple.clone() else { panic!("Impossible") };
+ let mut new_steps = steps.to_vec();
+ new_steps.append(&mut tail.to_vec());
+ run(new_steps.to_vec(), Value::Pair(Box::new((*v0, v1))), s)
+ },
+ (None, v, None) => v,
+ _ => panic!("Impossible"),
+ }
+}
+
+
+pub fn main() {
+ use Term::*;
+ println!("CAM:");
+
+ let t1 = Car(Box::new(MkPair(Box::new((Lit(1), Lit(2))))));
+ println!("t1: {:?}", t1.eval());
+
+ let t2 = App(Box::new((App(Box::new((Lam(Box::new(Var(0))), Lam(Box::new(Var(0)))))), Lam(Box::new(Var(0))))));
+ println!("t2: {:?}", t2.eval());
+}