Function ctrs::compose[][src]

pub fn compose<F: 'static, G: 'static, Fv, Gv, V>(
    f: F,
    g: G
) -> Box<Fn(Fv) -> V> where
    F: Fn(Fv) -> Gv,
    G: Fn(Gv) -> V, 

Composition is the heart of categorical computation.

Overview

Our definition of composition may appear confusing at first, but let's break it down. We start by defining generic types for our two input functions. These areF and G, respectively. These have a 'static lifetime because we have to ensure that the borrow checker does not let these types out of scope before computation has finished. Next, we have types Fv and Gv, which represent the types for the return values for each of the functions F and G. Finally, we have our output type V, which is the result we want. We pass the functions F and G as parameters f and g.

Still with me?

Next, the return value is a Box of the generic Fn type that takes an Fv to a V. We have to box the return value because we do not know how much size it could occupy on the stack (thus we allocate to the heap). Finally, we implement trait bounds on F and G, specifying how the chain should compose: F takes an Fv to a Gv, and then G takes a Gv to V.

Phew! 😅

Let's now see how this looks in practice using an example.

Example

use ctrs::{id, compose};

// Let's first define a trivial incrementer function.
fn inc(x: i32) -> i32 {
  x + 1
}

// and cover our bases by confirming inc works as expected.
let x = 1;
assert_eq!(inc(x), 2);

// Since we are composing functions on a given value, the syntax is
// compose(A, B)(V). Knowing this, our passing test looks like:
assert_eq!(compose(id, inc)(1), 2);

We can extend this idea! Let's take the situation where we've also defined an admittedly contrived double function, and want to compose its behavior with our existing incrementer. Mathematicians sometimes call the composition operator one might find in Haskell after, and understanding the way in which the function associates is indeed g after f.

fn double(x: i32) -> i32 {
   x * 2
}

let x = 1;
assert_eq!(compose(inc, double)(1), 4);