-
-
Notifications
You must be signed in to change notification settings - Fork 442
Thinking Functionally: Function composition
We've mentioned function composition a number of times in passing now, but what does it actually mean? It can seem quite intimidating at first, but it is actually quite simple.
Say that you have a function f
that maps from type T1
to type T2
, and say that you also have a function g
that maps from type T2
to type T3
. Then you can connect the output of f
to the input of g
, creating a new function that maps from type T1
to type T3
.
Here's an example:
static float f(int x) => x * 3.0f; // f is int->float
static bool g(float x) => x > 4.0f; // g is float->bool
We can create a new function h
that takes the output of f
and uses it as the input for g
.
static bool h(int x)
{
var y = f(x);
return g(y);
}
A much more compact way is this:
static bool h(int x) => g(f(x)); // h is int->bool
//test
var x = h(1); // x == false
var y = h(2); // y == true
So far, so straightforward. What is interesting is that we can define a new function called compose
that, given functions f
and g
, combines them in this way without even knowing their signatures.
static Func<A, C> compose<A, B, C>(Func<A, B> a, Func<B, C> b) =>
v => b(a(v));
compose
is part ofLanguageExt.Prelude
and can be used to compose up to 7 functions (Note also that this generic composition operation is only possible because every function has one input and one output. This approach would not be possible in a non-functional language.)