Combinator for multiple closure variants

Hello! I have created a combinator that increments a calculated i32 value.

fn increment(f: impl FnOnce(i32) -> i32) -> impl FnOnce(i32) -> i32 {
    move |x: i32| f(x) + 1
}

However, sometimes the f passed in is an Fn instead of an FnOnce. In this case, I would like the whole function returned by the combinator to also be an Fn. If I simply reference the Fn to get an FnOnce, I can call my original increment but it will return me an FnOnce — I want an Fn.

fn increment(f: impl Fn(i32) -> i32) -> impl Fn(i32) -> i32 {
    move |x: i32| f(x) + 1
}

Clearly I cannot have two functions with the same name! Is there a way to create a unified version of the increment combinator that will use the first version if f is FnOnce and the second version if f is Fn?

You would need to have a single signature that correctly reveals all of these behaviors. If you were dealing with a normal trait you could implement on your own types, this would be possible with an approach looking like this:

  1. Create your own struct with a field for the closure and make it generic over the closure.
  2. Make an impl<F: FnOnce()> FnOnce() for MyStruct<F>
  3. Make an impl<F: Fn()> Fn() for MyStruct<F>
  4. Explicitly return that type instead of an impl FnOnce()

This way the compiler can deduce whether the type is Fn by looking at the generic parameter on it. Unfortunately it is not possible to manually implement the Fn traits on your own types, so this is not possible.

Note that the actual type of the closure you're implementing actually does exactly as above, so if you could name the type of the closure explicitly that would also work. Unfortunately the type of the closure is not nameable, so this is also not possible.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.