Implement basic beta reduction
This commit is contained in:
parent
0706056111
commit
f6fbe890b5
242
src/main.rs
242
src/main.rs
@ -1,113 +1,169 @@
|
|||||||
use std::cell::RefCell;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct ArgCell(Rc<RefCell<Option<EitherValue>>>);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Lambda {
|
|
||||||
arg: ArgCell,
|
|
||||||
expression: Expression
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum EitherValue {
|
|
||||||
Lambda(Lambda),
|
|
||||||
Expression(Expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum Expression {
|
pub struct ArgGen(usize);
|
||||||
Valued(ArgCell),
|
|
||||||
Expression(ArgCell, ArgCell)
|
impl ArgGen {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
ArgGen(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArgCell {
|
pub fn next(&mut self) -> usize {
|
||||||
fn lambda(value: Lambda) -> Self {
|
let current = self.0;
|
||||||
ArgCell(Rc::new(RefCell::new(Some(EitherValue::Lambda(value)))))
|
self.0 += 1;
|
||||||
}
|
current
|
||||||
|
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for ArgCell {
|
#[derive(Debug)]
|
||||||
fn clone(&self) -> Self {
|
pub enum Expression {
|
||||||
let cell = self.0.borrow();
|
Paren(Box<Expression>),
|
||||||
if cell.is_some() {
|
Variable(usize),
|
||||||
Self(self.0.clone())
|
Call(Box<Expression>, Box<Expression>),
|
||||||
} else {
|
Lambda(usize, Box<Expression>),
|
||||||
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<EitherValue>) -> 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(_))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
fn new_valued(value: ArgCell) -> Self {
|
pub fn paren(expr: Expression) -> Self {
|
||||||
Self::Valued(value)
|
Expression::Paren(Box::new(expr))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_expression(callee: ArgCell, argument: ArgCell) -> Self {
|
pub fn variable(index: usize) -> Self {
|
||||||
Self::Expression(callee, argument)
|
Expression::Variable(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_beta_reduce(&self) -> bool {
|
pub fn call(func: Expression, arg: Expression) -> Self {
|
||||||
// TODO: Clean this up
|
Expression::Call(Box::new(func), Box::new(arg))
|
||||||
matches!(self, Self::Expression(callee, _) if callee.0.borrow().is_some() && callee.0.borrow().as_ref().unwrap().is_lambda())
|
}
|
||||||
|
|
||||||
|
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<usize, usize>, 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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// (lx.(ly.x(xy))) (lz.z)
|
pub fn substitute(&self, index: usize, replacement: &Expression, arg_gen: &mut ArgGen) -> Expression {
|
||||||
// -> (ly.(lz.z)((lw.w)y))
|
match self {
|
||||||
// -> (ly.(lz.z)y)
|
Expression::Paren(expr) => Expression::paren(expr.substitute(index, replacement, arg_gen)),
|
||||||
// -> (ly.y)
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
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 mut arg_gen = &mut ArgGen::new();
|
||||||
let reduced = func.beta_reduce(func_identity);
|
let a = arg_gen.next();
|
||||||
dbg!(reduced);
|
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());
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user