3

I can do something like this:

fn func() -> (Vec<i32>, Vec<i32>) {
    let mut u = vec![0;5];
    let mut v = vec![0;5];

    fn foo(u: &mut [i32], v: &mut [i32], i: usize, j: usize) {
        for k in i+1..u.len() {
            u[k] += 1;
            bar(u, v, k, j);
        }
    }
    fn bar(u: &mut [i32], v: &mut [i32], i: usize, j: usize) {
        for k in j+1..v.len() {
            v[k] += 1;
            foo(u, v, i, k);
        }
    }
    foo(&mut u, &mut v, 0, 0);
    (u,v)
}

fn main() {
    let (u,v) = func();
    println!("{:?}", u);
    println!("{:?}", v);
}

but I would prefer to do something like this:

fn func() -> (Vec<i32>, Vec<i32>) {
    let mut u = vec![0;5];
    let mut v = vec![0;5];

    let foo = |i, j| {
        for k in i+1..u.len() {
            u[k] += 1;
            bar(k, j);
        }
    };
    let bar = |i, j| {
        for k in j+1..v.len() {
            v[k] += 1;
            foo(i, k);
        }
    };
    foo(0, 0);
    (u,v)
}

fn main() {
    let (u,v) = func();
    println!("{:?}", u);
    println!("{:?}", v);
}

The second example doesn't compile with the error: unresolved name bar. In my task I can do it through one recursion, but it will not look clear. Does anyone have any other suggestions?

vessd
  • 215
  • 3
  • 7
  • Maybe it would be better if you specified in the question title that the problem is mutual recursion? – Alex Knauth Jan 18 '16 at 06:00
  • Thank you, I just did not know how it's called – vessd Jan 18 '16 at 06:11
  • 1
    I was curious, so I searched and found this [question about normal single recursion with closures](https://stackoverflow.com/questions/16946888/recursive-closure-in-rust). That's not supported directly either, though this [answer](https://stackoverflow.com/questions/16946888/recursive-closure-in-rust/16953239#16953239) points out a way to do it by passing the function as an argument to itself. – Alex Knauth Jan 18 '16 at 06:27
  • @D101101 I'm curious if this is possible and how the end result would look, but I doubt it would look pretty. If your goal is clarity as I think you're saying, your first approach with function pointers is probably best... – Paolo Falabella Jan 18 '16 at 08:58
  • @PaoloFalabella Yes, I want to make the code cleaner. Thanks for your help. – vessd Jan 18 '16 at 09:33
  • I tried `let bar; let foo = [closure]; bar = [closure];`, but unfortunately, it fails to compile with `error: the type of this value must be known in this context` on the call to `bar` in the first closure, and it's not possible to specify the type of `bar`, since it's an anonymous generated type. – Francis Gagné Jan 18 '16 at 11:45
  • @FrancisGagné you might work around that specific problem [with trait objects](http://is.gd/iA1q4e). Unfortunately even if you can declare the type of bar before foo, it's still an error to capture it while it is uninitialized. – Paolo Falabella Jan 18 '16 at 11:56

2 Answers2

3

I have a solution for mutually recursive closures, but it doesn't work with multiple mutable borrows, so I couldn't extend it to your example.

There is a way to use define mutually recursive closures, using an approach similar to how this answer does single recursion. You can put the closures together into a struct, where each of them takes a borrow of that struct as an extra argument.

fn func(n: u32) -> bool {
    struct EvenOdd<'a> {
        even: &'a Fn(u32, &EvenOdd<'a>) -> bool,
        odd: &'a Fn(u32, &EvenOdd<'a>) -> bool
    }
    let evenodd = EvenOdd {
        even: &|n, evenodd| {
            if n == 0 {
                true
            } else {
                (evenodd.odd)(n - 1, evenodd)
            }
        },
        odd: &|n, evenodd| {
            if n == 0 {
                false
            } else {
                (evenodd.even)(n - 1, evenodd)
            }
        }
    };
    (evenodd.even)(n, &evenodd)
}

fn main() {
    println!("{}", func(5));
    println!("{}", func(6));
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Alex Knauth
  • 8,133
  • 2
  • 16
  • 31
  • Well, this is the answer to my question, but unfortunately not the solution for me. – vessd Jan 19 '16 at 07:28
  • Yes. It might work for you if you passed the mutable borrows around as extra arguments as well, but then you might as well use local `fn`s instead, which was your first solution in your question. – Alex Knauth Jan 19 '16 at 15:00
3

While defining mutually recursive closures works in some cases, as demonstrated in the answer by Alex Knauth, I don't think that's an approach you should usually take. It is kind of opaque, has some limitations pointed out in the other answer, and it also has a performance overhead since it uses trait objects and dynamic dispatch at runtime.

Closures in Rust can be thought of as functions with associated structs storing the data you closed over. So a more general solution is to define your own struct storing the data you want to close over, and define methods on that struct instead of closures. For this case, the code could look like this:

pub struct FooBar {
    pub u: Vec<i32>,
    pub v: Vec<i32>,
}

impl FooBar {
    fn new(u: Vec<i32>, v: Vec<i32>) -> Self {
        Self { u, v }
    }

    fn foo(&mut self, i: usize, j: usize) {
        for k in i+1..self.u.len() {
            self.u[k] += 1;
            self.bar(k, j);
        }
    }

    fn bar(&mut self, i: usize, j: usize) {
        for k in j+1..self.v.len() {
            self.v[k] += 1;
            self.foo(i, k);
        }
    }
}

fn main() {
    let mut x = FooBar::new(vec![0;5], vec![0;5]);
    x.foo(0, 0);
    println!("{:?}", x.u);
    println!("{:?}", x.v);
}

(Playground)

While this can get slightly more verbose than closures, and requires a few more explicit type annotations, it's more flexible and easier to read, so I would generally prefer this approach.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841