From f6fbe890b58cd57a0fda09e5e90a3f3ed072ab2a Mon Sep 17 00:00:00 2001 From: Gabriel Tofvesson Date: Sun, 24 Aug 2025 14:06:26 +0200 Subject: [PATCH] Implement basic beta reduction --- src/main.rs | 240 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 148 insertions(+), 92 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3403a39..91781e1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,113 +1,169 @@ -use std::cell::RefCell; -use std::rc::Rc; - -#[derive(Debug)] -struct ArgCell(Rc>>); - -#[derive(Debug)] -struct Lambda { - arg: ArgCell, - expression: Expression -} - -#[derive(Debug)] -enum EitherValue { - Lambda(Lambda), - Expression(Expression) -} +use std::collections::HashMap; #[derive(Debug, Clone)] -enum Expression { - Valued(ArgCell), - Expression(ArgCell, ArgCell) -} +pub struct ArgGen(usize); -impl ArgCell { - fn lambda(value: Lambda) -> Self { - ArgCell(Rc::new(RefCell::new(Some(EitherValue::Lambda(value))))) +impl ArgGen { + pub fn new() -> Self { + ArgGen(0) } - fn expression(expression: Expression) -> Self { - ArgCell(Rc::new(RefCell::new(Some(EitherValue::Expression(expression))))) - } - - fn future() -> Self { - ArgCell(Rc::new(RefCell::new(None))) - } - - fn copy_retain(&self) -> Self { - Self(self.0.clone()) + pub fn next(&mut self) -> usize { + let current = self.0; + self.0 += 1; + current } } -impl Clone for ArgCell { - fn clone(&self) -> Self { - let cell = self.0.borrow(); - if cell.is_some() { - Self(self.0.clone()) - } else { - Self(Rc::new(RefCell::new(None))) - } - } -} - -impl Lambda { - fn new(expression: impl FnOnce(ArgCell) -> Expression) -> Self { - let cell = ArgCell::future(); - Self { - arg: cell.copy_retain(), - expression: expression(cell) - } - } - - fn beta_reduce(self, argument: Option) -> Expression { - *self.arg.0.borrow_mut() = argument; - self.expression - } -} - -impl Clone for Lambda { - fn clone(&self) -> Self { - Self::new(|_| self.expression.clone()) - } -} - -impl EitherValue { - fn is_lambda(&self) -> bool { - matches!(*self, EitherValue::Lambda(_)) - } - - fn is_expression(&self) -> bool { - matches!(*self, EitherValue::Expression(_)) - } +#[derive(Debug)] +pub enum Expression { + Paren(Box), + Variable(usize), + Call(Box, Box), + Lambda(usize, Box), } impl Expression { - fn new_valued(value: ArgCell) -> Self { - Self::Valued(value) + pub fn paren(expr: Expression) -> Self { + Expression::Paren(Box::new(expr)) } - fn new_expression(callee: ArgCell, argument: ArgCell) -> Self { - Self::Expression(callee, argument) + pub fn variable(index: usize) -> Self { + Expression::Variable(index) } - fn can_beta_reduce(&self) -> bool { - // TODO: Clean this up - matches!(self, Self::Expression(callee, _) if callee.0.borrow().is_some() && callee.0.borrow().as_ref().unwrap().is_lambda()) + pub fn call(func: Expression, arg: Expression) -> Self { + Expression::Call(Box::new(func), Box::new(arg)) + } + + pub fn lambda(arg_index: usize, body: Expression) -> Self { + Expression::Lambda(arg_index, Box::new(body)) + } + + pub fn deep_clone(&self, arg_map: &mut HashMap, arg_gen: &mut ArgGen) -> Self { + match self { + Expression::Paren(expr) => Expression::paren(expr.deep_clone(arg_map, arg_gen)), + Expression::Variable(i) => { + if let Some(new_index) = arg_map.get(i) { + Expression::variable(*new_index) + } else { + Expression::variable(*i) + } + } + Expression::Call(func, arg) => Expression::call( + func.deep_clone(arg_map, arg_gen), + arg.deep_clone(arg_map, arg_gen), + ), + Expression::Lambda(arg_index, body) => { + let new_index = arg_gen.next(); + + arg_map.insert(*arg_index, new_index); + let cloned_body = body.deep_clone(arg_map, arg_gen); + arg_map.remove(arg_index); + Expression::Lambda(new_index, Box::new(cloned_body)) + } + } + } + + pub fn substitute(&self, index: usize, replacement: &Expression, arg_gen: &mut ArgGen) -> Expression { + match self { + Expression::Paren(expr) => Expression::paren(expr.substitute(index, replacement, arg_gen)), + Expression::Variable(i) => { + if *i == index { + replacement.deep_clone(&mut HashMap::new(), arg_gen) + } else { + Expression::variable(*i) + } + } + Expression::Call(func, arg) => { + if let Expression::Lambda(arg_index, body) = &**func { + if *arg_index == index { + let new_body = body.substitute(index, replacement, arg_gen); + let new_arg = arg.substitute(index, replacement, arg_gen); + new_body.substitute(*arg_index, &new_arg, arg_gen) + } else { + Expression::call( + func.substitute(index, replacement, arg_gen), + arg.substitute(index, replacement, arg_gen), + ) + } + } else { + Expression::call( + func.substitute(index, replacement, arg_gen), + arg.substitute(index, replacement, arg_gen), + ) + } + }, + Expression::Lambda(arg_index, body) => { + if *arg_index == index { + body.substitute(index, replacement, arg_gen) + } else { + Expression::Lambda( + *arg_index, + Box::new(body.substitute(index, replacement, arg_gen)), + ) + } + } + } + } + + pub fn find_next_reducible(&self) -> Option<(usize, &Expression)> { + match self { + Expression::Call(func, arg) => match **func { + Expression::Lambda(arg_index, _) => Some((arg_index, arg.as_ref())), + _ => func.find_next_reducible().or_else(|| arg.find_next_reducible()), + }, + Expression::Paren(expr) => expr.find_next_reducible(), + Expression::Lambda(_, body) => body.find_next_reducible(), + Expression::Variable(_) => None, + } } } -// (lx.(ly.x(xy))) (lz.z) -// -> (ly.(lz.z)((lw.w)y)) -// -> (ly.(lz.z)y) -// -> (ly.y) +impl ToString for Expression { + fn to_string(&self) -> String { + match self { + Expression::Paren(expr) => format!("{{{}}}", expr.to_string()), + Expression::Variable(i) => format!("x{}", i), + Expression::Call(func, arg) => format!("({} {})", func.to_string(), arg.to_string()), + Expression::Lambda(arg_index, body) => format!("[λx{}. {}]", arg_index, body.to_string()), + } + } +} fn main() { - // Lambda_x { Expression { Lambda_y { Expression { x(Expression(x, y)) } } } } - let func = Lambda::new(|x| - Expression::new_valued(ArgCell::lambda(Lambda::new(|y| Expression::new_expression(x.copy_retain(), ArgCell::expression(Expression::Expression(x, y)))))) - ); - let func_identity = Some(EitherValue::Lambda(Lambda::new(Expression::Valued))); - let reduced = func.beta_reduce(func_identity); - dbg!(reduced); + let mut arg_gen = &mut ArgGen::new(); + let a = arg_gen.next(); + let b = arg_gen.next(); + let c = arg_gen.next(); + let s1 = Expression::lambda(a, Expression::lambda(b, Expression::lambda(c, + Expression::call( + Expression::variable(b), + Expression::call( + Expression::call( + Expression::variable(a), + Expression::variable(b) + ), + Expression::variable(c), + ), + )))); + let s2 = Expression::call(s1.deep_clone(&mut HashMap::new(), &mut arg_gen), s1.deep_clone(&mut HashMap::new(), &mut arg_gen)); + let s3 = Expression::call(s1.deep_clone(&mut HashMap::new(), &mut arg_gen), s2.deep_clone(&mut HashMap::new(), &mut arg_gen)); + + let z = arg_gen.next(); + let w = arg_gen.next(); + let zero = Expression::lambda(z, Expression::lambda(w, Expression::variable(w))); + let one = Expression::lambda(z, Expression::lambda(w, Expression::call(Expression::variable(z), Expression::variable(w)))); + let two = Expression::lambda(z, Expression::lambda(w, Expression::call(Expression::variable(z), Expression::call(Expression::variable(z), Expression::variable(w))))); + let three = Expression::lambda(z, Expression::lambda(w, Expression::call(Expression::variable(z), Expression::call(Expression::variable(z), Expression::call(Expression::variable(z), Expression::variable(w)))))); + let four = Expression::lambda(z, Expression::lambda(w, Expression::call(Expression::variable(z), Expression::call(Expression::variable(z), Expression::call(Expression::variable(z), Expression::call(Expression::variable(z), Expression::variable(w))))))); + + + let mut full_expr = Expression::call(s3, two); + println!("Solving: {}", full_expr.to_string()); + + while let Some((index, reduced)) = full_expr.find_next_reducible() { + full_expr = full_expr.substitute(index, reduced, &mut arg_gen); + } + println!("-> {}", full_expr.to_string()); }