I am trying to implement a y-combinator in Rust to help me write recursive closure. After referencing some existing implementations, seems that the following code works just fine:
fn ycall<Arg, Out>(arg: Arg, f: &impl Fn(&dyn Fn(Arg) -> Out, Arg) -> Out) -> Out {
(f)(&|arg| ycall(arg, f), arg)
}
fn ycomb<Arg, Out>(f: impl Fn(&dyn Fn(Arg) -> Out, Arg) -> Out) -> impl Fn(Arg) -> Out {
move |arg| ycall(arg, &f)
}
fn main() {
let base = 2;
let pow_base = ycomb::<i32, i32>(|f, x| if x == 0 { 1 } else { base * f(x - 1) });
assert_eq!(1024, pow_base(10));
}
However, it does not seem to work properly when Arg is a reference. For example, the following code yields some error:
fn main() {
let base = 2;
let pow_base = ycomb::<&i32, i32>(|f, x| if *x == 0 { 1 } else { base * f(&(*x - 1)) });
assert_eq!(1024, pow_base(&10));
}
// error[E0716]: temporary value dropped while borrowed
// --> src/main.rs:11:80
// |
// 11 | let pow_base = ycomb::<&i32, i32>(|f, x| if *x == 0 { 1 } else { base * f(&(x - 1)) });
// | - ---^^^^^^^- - temporary value is freed at the end of this statement
// | | | |
// | | | creates a temporary value which is freed while still in use
// | has type `&dyn Fn(&'1 i32) -> i32` argument requires that borrow lasts for `'1`
If I understand correctly, it seems that the passed function wants to borrow Arg even after the function call ends, which is not something I needed here.
How could I modify how the combinator is implemented or called for it to be able to work with reference type parameter?