use std::rc::Rc; /* struct R<'a> { b: &'a dyn Fn() -> R<'a>, } #[derive(Copy, Clone)] struct Foo {} impl<'a> Foo { // These are valid, but not especially useful (if I am // transferring ownership then I cannot have any branching): fn fn1(self) -> R<'a> { R { b: & move || self.fn1() } } fn fn2(self) -> R<'a> { R { b: &|| self.fn2() } } } */ // Below (using box instead of a trait object) follows similar rules: struct S<'a> { b: Box S<'a>>, } #[derive(Copy, Clone)] struct Foo2 {} impl<'a> Foo2 { fn fn1(self) -> S<'a> { S { b: Box::new(move || self.fn1()) } } // Not valid (error[E0373]: closure may outlive the current // function, but it borrows `self`, which is owned by the current // function): //fn fn2(self) -> S<'a> { // S { b: Box::new(|| self.fn2()) } //} // Not valid: //fn fn3(&self) -> S<'a> { // S { b: Box::new(move || self.fn3()) } //} // Not valid: //fn fn4(&self) -> S<'a> { // S { b: Box::new(|| self.fn4()) } //} } struct T<'a> { b: Rc T<'a> + 'a>, } #[derive(Copy, Clone)] struct Foo3 {} impl<'a> Foo3 { fn fn1(self) -> T<'a> { T { b: Rc::new(move || self.fn1()) } } // Not valid (E0373): //fn fn2(self) -> T<'a> { // T { b: Rc::new(|| self.fn2()) } //} // Not valid: //fn fn3(&self) -> T<'a> { // T { b: Rc::new(move || self.fn3()) } //} // Not valid: //fn fn4(&self) -> T<'a> { // T { b: Rc::new(|| self.fn4()) } //} // But this is now valid because T can be cloned: fn fn5(self) -> (T<'a>, T<'a>) { let p = Rc::new(move || self.fn1()); let p2 = p.clone(); (T { b: p }, T { b: p2 }) } } // Further, this is now valid too (lifetimes removed): struct U { b: Rc U>, } #[derive(Copy, Clone)] struct Foo4 {} impl Foo4 { fn fn1(self) -> U { U { b: Rc::new(move || self.fn1()) } } fn fn5(self) -> (U, U) { let p = Rc::new(move || self.fn1()); let p2 = p.clone(); (U { b: p }, U { b: p2 }) } } // I can get rid of Copy/Clone if I use FnOnce: struct V { b: Rc V>, } struct Foo5 {} impl Foo5 { fn fn1(self) -> V { V { b: Rc::new(move || self.fn1()) } } fn fn2(self) -> (V, V) { let p = Rc::new(move || self.fn1()); let p2 = p.clone(); (V { b: p }, V { b: p2 }) } // and then either kind is fine: fn fn3(self) -> V { V { b: Rc::new(|| self.fn3()) } } fn fn4(self) -> (V, V) { let p = Rc::new(|| self.fn3()); let p2 = p.clone(); (V { b: p }, V { b: p2 }) // but this confuses me a bit. doesn't this then let me call // an FnOnce... more than once? } } // This is valid and I can recurse: struct W { b: Box W>, } struct Foo6 {} impl Foo6 { fn fn1(s: &Rc) -> W { let s2 = Rc::clone(&s); W { b: Box::new(move || Self::fn1(&s2)) } } fn fn2(s: &Rc) -> (W, W) { let s2 = Rc::clone(&s); let w2 = W { b: Box::new(move || Self::fn1(&s2)) }; let s3 = Rc::clone(&s); let w3 = W { b: Box::new(move || Self::fn1(&s3)) }; (w2, w3) } } fn foo6() { // Whatever (note that it doesn't automatically do Copy): struct State { v: u32, } // Purposely put state somewhere it goes out of scope: let s = { let s_orig = State { v: 105, }; Rc::new(s_orig) }; /* let fn1 = |f: &dyn Fn(&dyn Fn() -> W) -> (&dyn Fn() -> W)| -> (&dyn Fn() -> W) { &(|| -> W { let s2 = Rc::clone(&s); W { b: Box::new(move || f(f)) } }) }; let f2 = fn1(fn1); */ } fn foo7(t: impl Clone) -> impl Clone { t.clone() } fn foo7b(t: T) -> T { t.clone() } fn foo7c(t: T) -> T where T: Clone { t.clone() } // A simple implementation of the Y Combinator // λf.(λx.xx)(λx.f(xx)) // <=> λf.(λx.f(xx))(λx.f(xx)) // CREDITS: A better version of the previous code that was posted here, with detailed explanation. // See and also . // A function type that takes its own type as an input is an infinite recursive type. // We introduce a trait that will allow us to have an input with the same type as self, and break the recursion. // The input is going to be a trait object that implements the desired function in the interface. // NOTE: We will be coercing a reference to a closure into this trait object. trait Apply { fn apply(&self, f: &dyn Apply, t: T) -> R; } // In Rust, closures fall into three kinds: FnOnce, FnMut and Fn. // FnOnce assumed to be able to be called just once if it is not Clone. It is impossible to // write recursive FnOnce that is not Clone. // All FnMut are also FnOnce, although you can call them multiple times, they are not allow to // have a reference to themselves. So it is also not possible to write recursive FnMut closures // that is not Clone. // All Fn are also FnMut, and all closures of Fn are also Clone. However, programmers can create // Fn objects that are not Clone // This will work for all Fn objects, not just closures // And it is a little bit more efficient for Fn closures as it do not clone itself. impl Apply for F where F: Fn(&dyn Apply, T) -> R { fn apply(&self, f: &dyn Apply, t: T) -> R { self(f, t) // NOTE: Each letter is an individual symbol. // (λx.(λy.xxy))(λx.(λy.f(λz.xxz)y))t // => (λx.xx)(λx.f(xx))t // => (Yf)t } } // This works for all closures that is Clone, and those are Fn. // impl Apply for F where F: FnOnce( &Apply, T ) -> R + Clone { // fn apply( &self, f: &Apply, t: T ) -> R { // (self.clone())( f, t ) // // If we were to pass in self as f, we get - // // NOTE: Each letter is an individual symbol. // // λf.λt.sft // // => λs.λt.sst [s/f] // // => λs.ss // } // } // Before 1.26 we have some limitations and so we need some workarounds. But now impl Trait is stable and we can // write the following: fn y(f:impl Fn(&dyn Fn(T) -> R, T) -> R) -> impl Fn(T) -> R { move |t| ( |x: &dyn Apply, y| x.apply(x, y) ) ( &|x: &dyn Apply, y| f( &|z| x.apply(x,z), y ), t ) } // fn y(f:impl FnOnce(&Fn(T) -> R, T) -> R + Clone) -> impl FnOnce(T) -> R { // |t| (|x: &Apply,y| x.apply(x,y)) // (&move |x:&Apply,y| f(&|z| x.apply(x,z), y), t) // // NOTE: Each letter is an individual symbol. // // (λx.(λy.xxy))(λx.(λy.f(λz.xxz)y))t // // => (λx.xx)(λx.f(xx))t // // => (Yf)t // } // Previous version removed as they are just hacks when impl Trait is not available. fn fac(n: usize) -> usize { let almost_fac = |f: &dyn Fn(usize) -> usize, x| if x == 0 { 1 } else { x * f(x - 1) } ; let fac = y( almost_fac ); fac(n) } fn fib( n: usize ) -> usize { let almost_fib = |f: &dyn Fn(usize) -> usize, x| if x < 2 { 1 } else { f(x - 2) + f(x - 1) }; let fib = y(almost_fib); fib(n) } fn optimal_fib( n: usize ) -> usize { let almost_fib = |f: &dyn Fn((usize,usize,usize)) -> usize, (i0,i1,x)| match x { 0 => i0, 1 => i1, x => f((i1,i0+i1, x-1)) } ; let fib = |x| y(almost_fib)((1,1,x)); fib(n) } fn test_y() { println!("{}", fac(10)); println!("{}", fib(10)); println!("{}", optimal_fib(10)); }