RosettaCodeData/Task/Church-numerals/Rust/church-numerals.rust
2023-07-01 13:44:08 -04:00

98 lines
2.3 KiB
Text

use std::rc::Rc;
use std::ops::{Add, Mul};
#[derive(Clone)]
struct Church<'a, T: 'a> {
runner: Rc<dyn Fn(Rc<dyn Fn(T) -> T + 'a>) -> Rc<dyn Fn(T) -> T + 'a> + 'a>,
}
impl<'a, T> Church<'a, T> {
fn zero() -> Self {
Church {
runner: Rc::new(|_f| {
Rc::new(|x| x)
})
}
}
fn succ(self) -> Self {
Church {
runner: Rc::new(move |f| {
let g = self.runner.clone();
Rc::new(move |x| f(g(f.clone())(x)))
})
}
}
fn run(&self, f: impl Fn(T) -> T + 'a) -> Rc<dyn Fn(T) -> T + 'a> {
(self.runner)(Rc::new(f))
}
fn exp(self, rhs: Church<'a, Rc<dyn Fn(T) -> T + 'a>>) -> Self
{
Church {
runner: (rhs.runner)(self.runner)
}
}
}
impl<'a, T> Add for Church<'a, T> {
type Output = Church<'a, T>;
fn add(self, rhs: Church<'a, T>) -> Church<T> {
Church {
runner: Rc::new(move |f| {
let self_runner = self.runner.clone();
let rhs_runner = rhs.runner.clone();
Rc::new(move |x| (self_runner)(f.clone())((rhs_runner)(f.clone())(x)))
})
}
}
}
impl<'a, T> Mul for Church<'a, T> {
type Output = Church<'a, T>;
fn mul(self, rhs: Church<'a, T>) -> Church<T> {
Church {
runner: Rc::new(move |f| {
(self.runner)((rhs.runner)(f))
})
}
}
}
impl<'a, T> From<i32> for Church<'a, T> {
fn from(n: i32) -> Church<'a, T> {
let mut ret = Church::zero();
for _ in 0..n {
ret = ret.succ();
}
ret
}
}
impl<'a> From<&Church<'a, i32>> for i32 {
fn from(c: &Church<'a, i32>) -> i32 {
c.run(|x| x + 1)(0)
}
}
fn three<'a, T>() -> Church<'a, T> {
Church::zero().succ().succ().succ()
}
fn four<'a, T>() -> Church<'a, T> {
Church::zero().succ().succ().succ().succ()
}
fn main() {
println!("three =\t{}", i32::from(&three()));
println!("four =\t{}", i32::from(&four()));
println!("three + four =\t{}", i32::from(&(three() + four())));
println!("three * four =\t{}", i32::from(&(three() * four())));
println!("three ^ four =\t{}", i32::from(&(three().exp(four()))));
println!("four ^ three =\t{}", i32::from(&(four().exp(three()))));
}