Photograph by Sepand Bakhtiari, CC BY-SA 4.0, via Wikimedia Commons
The K-Combinator
Combinators are functional patterns that glue (AKA compose) together functions. These patterns promote single responsibility and decoupling.
The K-Combinator is more commonly known as the Constant Combinator. It is formally known as the Kestrel Combinator. The K-Combinator can be defined in C# as:
Func<dynamic, T> Constant<T>(T x) => _ => x;
It's a function that always returns the initial value when called with any input. In a sense, it is a mapping of the set of all values to x. Simple!
Side Effects
One common pattern I've seen this used is in the implementation of the Tee
function. Tee
is a way of causing side effects in a pipeline of functions. This can aide in code readability by keeping your control flow in top to bottom direction, while explicitly communicating that a side effect is happening.
Func<T, T> Tee<T>(Action sideEffect)
=> input
=> Constant<T>(input)(sideEffect.Invoke(input));
// sometime later...
var ItemForSale = ...
var ExecutePayment = Tee((total) => ProcessTransaction(total));
var Total = ExecutePayment(CalculateTotal(ItemForSale));
In this case, the Tee
would process the transaction, while passing the input as the result. Using this in combination with the T-combinator ( See Part I in this series ) and you can get something like this:
var Total = ItemForSale
.Pipe(CalculateTotal)
.Pipe(ExecutePayment)
// renaming Pipe to Then
var Total = ItemForSale.
Then(CalculateTotal).
Then(ExecutePayment)
In the end, what it buys you is:
- decoupling of functions
- code that reads from top to bottom
- lazy evaluation of side effects
Awesome!