I found a implementation of Y-Combinator which supports Fn. However I want to have a version of FnMut.
However, FnMut can not be wrapped into Rc
, so I wrap them in Rc<RefCell>
. The following code can make a[i] = i
in a recursive way. It is the simplest code I have found to test if we can call itself inside a closure.
// test code part
let mut a = vec![0; 5];
let n = a.len();
y_mut(Rc::new(RefCell::new(|f: Rc<RefCell<dyn FnMut(usize)>>| {
move |i| {
if i < n {
a[i] = i;
((*f).borrow_mut())(i + 1);
}
}
})))(0);
println!("a is {:?}", a);
And this my version of y_mut
, derived from the demo.
fn y_mut<A, O, F>(f: Rc<RefCell<dyn FnMut(Rc<RefCell<dyn FnMut(A) -> O>>) -> F>>) -> impl FnMut(A) -> O
where
F: FnMut(A) -> O,
F: 'static,
A: 'static,
O: 'static,
{
struct X<F>(Rc<RefCell<dyn FnMut(X<F>) -> F>>);
impl<F> Clone for X<F> {
fn clone(&self) -> Self {
Self(Rc::clone(&self.0))
}
}
impl<F> X<F> {
fn call(&self, x: Self) -> F {
((*self.0).borrow_mut())(x)
}
}
let f = Rc::new(RefCell::new(move |x: X<F>| {
let mut ff = (*f).borrow_mut();
ff(Rc::new(RefCell::new(move |a| (x.call(x.clone()))(a))))
}));
let x = X(f);
(|x: X<F>| x.call(x.clone()))(x)
}
However, this code can't compile, since |f: Rc<RefCell<dyn FnMut(usize)>>|
only implments FnOnce, rather than FnMut. I wonder how to fix that?