RosettaCodeData/Task/Y-combinator/Rust/y-combinator.rust

45 lines
1.1 KiB
Plaintext

use std::sync::Arc;
use std::boxed::Box;
use std::clone::Clone;
//Arc<Box<Closure>>
#[macro_export]
macro_rules! abc {
($x:expr) => (Arc::new(Box::new($x)));
}
#[derive(Clone)]
pub enum Mu<T> {
Roll(Arc<Box<Fn(Mu<T>)->T>>),
}
pub fn unroll<T>(Mu::Roll(f): Mu<T>) -> Arc<Box<Fn(Mu<T>)->T>> {f.clone()}
pub type Func<A, B> = Arc<Box<Fn(A)->B>>;
pub type RecFunc<A, B> = Arc<Box<Fn(Func<A, B>) -> Func<A, B>>>;
pub fn y<A, B>(f: RecFunc<A, B>) -> Func<A, B> {
let g:Arc<Box<Fn(Mu<Func<A, B>>)->Func<A, B>>> = abc!(move |x : Mu<Func<A, B>>| -> Func<A, B> {
let f = f.clone();
abc!(move |a:A| -> B {
let f = f.clone();
f(unroll(x.clone())(x.clone()))(a)
})
});
g(Mu::Roll(g.clone()))
}
#[test]
fn fib_test() {
let fib : RecFunc<i32, i32> = abc!(|f| abc!(move |x| if (x<2) { 1 } else { f(x-1) + f(x-2)}));
let b = y(fib)(10);
assert_eq!(b, 89);
}
#[test]
fn fac_test() {
let fac : RecFunc<i32, i32> = abc!(|f| abc!(move |x| if (x==0) { 1 } else { f(x-1) * x }));
let c = y(fac)(10);
assert_eq!(c, 3628800);
}