use std::cmp::Ordering;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::hash::Hash;
use std::iter;
use std::ops::Deref;
use std::ops::DerefMut;
use crate::Term;
pub mod normal;
pub use normal::*;
pub trait BetaReduce<T> {
fn beta_reduce_step(&self, term: &mut Term<T>) -> bool;
fn beta_reduce(&self, term: &mut Term<T>) -> usize {
iter::from_fn(|| self.beta_reduce_step(term).then_some(())).count()
}
fn beta_reduce_while<P>(&self, term: &mut Term<T>, mut predicate: P) -> usize
where
P: FnMut(&Term<T>, usize) -> bool, {
(0..).into_iter()
.take_while(|count| predicate(term, *count) && self.beta_reduce_step(term))
.count()
}
fn beta_reduce_limit(&self, term: &mut Term<T>, limit: usize) -> usize {
self.beta_reduce_while(term, |_, count| count < limit)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Var<T> {
Bound(usize),
Free(T),
}
#[derive(Debug)]
pub enum LocalNamelessError {
InvalidVarIndex(usize),
InvalidAbsParam(usize),
}
pub type LocalNamelessTerm<T> = Term<Var<T>>;
impl<T: Clone> LocalNamelessTerm<T> {
pub fn beta_reduce<B: BetaReduce<Var<T>>>(&mut self, reducer: &B) -> usize {
reducer.beta_reduce(self)
}
pub fn beta_reduce_while<B, P>(&mut self, predicate: P, reducer: &B) -> usize
where
B: BetaReduce<Var<T>>,
P: FnMut(&Self, usize) -> bool, {
reducer.beta_reduce_while(self, predicate)
}
pub fn beta_reduce_limit<B: BetaReduce<Var<T>>>(&mut self, limit: usize, reducer: &B) -> usize {
reducer.beta_reduce_limit(self, limit)
}
pub fn beta_reduce_step<B: BetaReduce<Var<T>>>(&mut self, reducer: &B) -> bool {
reducer.beta_reduce_step(self)
}
fn open(&mut self, depth: usize, replacement: &Self) {
match self {
Self::Var(Var::Bound(index)) => match (*index).cmp(&depth) {
Ordering::Equal => *self = replacement.shifted(0, depth),
Ordering::Greater => *index -= 1,
Ordering::Less => (),
},
Self::Var(Var::Free(_)) => (),
Self::Abs(_, body) => body.open(depth + 1, replacement),
Self::App(func, arg) => {
func.open(depth, replacement);
arg.open(depth, replacement);
},
}
}
fn shifted(&self, depth: usize, amount: usize) -> Self {
match self {
Self::Var(Var::Bound(index)) => if *index >= depth {
Self::var(Var::Bound(*index + amount))
} else {
Self::var(Var::Bound(*index))
},
Self::Var(Var::Free(var)) => Self::var(Var::Free(var.clone())),
Self::Abs(param, body) => Self::abs(param.clone(), body.shifted(depth + 1, amount)),
Self::App(func, arg) => Self::app(func.shifted(depth, amount), arg.shifted(depth, amount)),
}
}
fn to_classic<'t>(&'t self, vars: &mut VecDeque<&'t T>) -> Result<Term<T>, LocalNamelessError> {
match self {
Self::Var(Var::Bound(index)) => match vars.get(*index) {
Some(&var) => Ok(Term::var(var.clone())),
None => Err(LocalNamelessError::InvalidVarIndex(*index)),
},
Self::Var(Var::Free(var)) => Ok(Term::var(var.clone())),
Self::Abs(param, body) => match param {
Var::Bound(index) => Err(LocalNamelessError::InvalidAbsParam(*index)),
Var::Free(param) => {
vars.push_front(param);
let term = Term::abs(param.clone(), body.to_classic(vars)?);
vars.pop_front();
Ok(term)
},
},
Self::App(func, arg) => Ok(Term::app(func.to_classic(vars)?, arg.to_classic(vars)?)),
}
}
}
impl<T: Clone + Eq + Hash> LocalNamelessTerm<T> {
pub fn rebind<'t>(&'t mut self, binds: &mut HashMap<T, Self>) {
match self {
Self::Var(Var::Bound(_)) => (),
Self::Var(Var::Free(var)) => if let Some(term) = binds.get(var) {
*self = term.clone();
},
Self::Abs(_, body) => body.rebind(binds),
Self::App(func, arg) => {
func.rebind(binds);
arg.rebind(binds);
},
}
}
}
impl<T: Clone + Eq> From<&Term<T>> for LocalNamelessTerm<T> {
fn from(classic: &Term<T>) -> Self {
classic.to_local_nameless(&mut VecDeque::new())
}
}
#[derive(Debug)]
pub struct ReducedTerm<T> {
pub count: usize,
pub term: Term<T>,
}
impl<T> AsRef<Term<T>> for ReducedTerm<T> {
fn as_ref(&self) -> &Term<T> {
&self.term
}
}
impl<T> Deref for ReducedTerm<T> {
type Target = Term<T>;
fn deref(&self) -> &Self::Target {
&self.term
}
}
impl<T> DerefMut for ReducedTerm<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.term
}
}
impl<T: Clone + Eq> Term<T> {
pub fn beta_reduced<B: BetaReduce<Var<T>>>(&self, reducer: &B) -> ReducedTerm<T> {
let mut local_nameless = LocalNamelessTerm::from(self);
ReducedTerm {
count: local_nameless.beta_reduce(reducer),
term: (&local_nameless).try_into().unwrap(),
}
}
pub fn beta_reduced_while<B, P>(&self, predicate: P, reducer: &B) -> ReducedTerm<T>
where
B: BetaReduce<Var<T>>,
P: FnMut(&LocalNamelessTerm<T>, usize) -> bool, {
let mut local_nameless = LocalNamelessTerm::from(self);
ReducedTerm {
count: local_nameless.beta_reduce_while::<B, P>(predicate, reducer),
term: (&local_nameless).try_into().unwrap(),
}
}
pub fn beta_reduced_limit<B: BetaReduce<Var<T>>>(&self, limit: usize, reducer: &B) -> ReducedTerm<T> {
let mut local_nameless = LocalNamelessTerm::from(self);
ReducedTerm {
count: local_nameless.beta_reduce_limit::<B>(limit, reducer),
term: (&local_nameless).try_into().unwrap(),
}
}
fn to_local_nameless<'t>(&'t self, vars: &mut VecDeque<&'t T>) -> LocalNamelessTerm<T> {
match self {
Self::Var(var) => match vars.iter().position(|¶m| param == var) {
Some(index) => LocalNamelessTerm::var(Var::Bound(index)),
None => LocalNamelessTerm::var(Var::Free(var.clone())),
},
Self::Abs(param, body) => {
vars.push_front(param);
let term = LocalNamelessTerm::abs(Var::Free(param.clone()), body.to_local_nameless(vars));
vars.pop_front();
term
},
Self::App(func, arg) => LocalNamelessTerm::app(func.to_local_nameless(vars), arg.to_local_nameless(vars)),
}
}
}
impl<T: Clone> TryFrom<&LocalNamelessTerm<T>> for Term<T> {
type Error = LocalNamelessError;
fn try_from(local_nameless: &LocalNamelessTerm<T>) -> Result<Self, Self::Error> {
local_nameless.to_classic(&mut VecDeque::new())
}
}
impl<T> From<ReducedTerm<T>> for Term<T> {
fn from(reduced: ReducedTerm<T>) -> Self {
reduced.term
}
}