Function composition is a major building block of functional programming. For instance (e.g. in Haskell f . g
gives you the same function as h x = f (g x)
, in scala g.andThen(f)
or f.compose(g)
do the same).
It would be nice to have a way to do this in rust, and ideally a way that the compiler understands so that the composed function can be optimized as a single unit.
I posted this issue: https://github.com/rust-lang/rust/issues/28226
which contains a suggestion on how this could be done (which I did not write).
#![feature(unboxed_closures, core)]
fn succ(x: i32) -> i32 { x + 1 }
fn sq(x: i32) -> i32 { x * x }
struct Compose<F, G>(F, G);
impl<R, M, A, F: FnOnce(M) -> R, G: FnOnce<A, Output=M>> FnOnce<A> for Compose<F, G> {
type Output = R;
extern "rust-call" fn call_once(self, args: A) -> R {
let Compose(f, g) = self;
f(g.call_once(args))
}
}
impl<R, M, A, F: FnMut(M) -> R, G: FnMut<A, Output=M>> FnMut<A> for Compose<F, G> {
extern "rust-call" fn call_mut(&mut self, args: A) -> R {
self.0(self.1.call_mut(args))
}
}
impl<R, M, A, F: Fn(M) -> R, G: Fn<A, Output=M>> Fn<A> for Compose<F, G> {
extern "rust-call" fn call(&self, args: A) -> R {
self.0(self.1.call(args))
}
}
fn main() {
let f = Compose(succ, sq);
println!("{} {}", f(5), f(6));
}
It was suggested I post this here for pre-RFC discussion (although a pull request to add this seems pretty straightforward).
One thing the above does not address is composing Box<FnBox()>, Box<Fn()>
which will likely come up in functional code where we have functions that return functions.