I’m back at it again with my functional programming shenanigans and this time I’m going to talk about PIPES!
We use them in the most important piece of hardware in any building — the mighty toilet and now also in our software development!
Truly a testament to the versatility of the proud PIPE!
In a blog post about functional programming I wrote before ( LINK ) I showed you an example:
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
With this ( partial ) explanation:
After that we reduceRight the array of gathered functions with the initial value — x, this is the same as reduce but starts at the end of the array and moves to the start because that is how ‘compose’ works if the opposite is more natural to you than you want to pipe functions.
They liked the “more natural” approach of piping functions instead of composing them and that’s how we got the Pipeline operator and it looks like this
I know what you’re thinking… ugly mofo but nevertheless very useful when coding functionally as we’ll soon find out.
The Obligatory MDN Section
Since I can’t take a dumb without looking it up on MDN ( big love MDN ) we’re gonna take a look at what it says for pipeline operator
The experimental pipeline operator
|>(currently at stage 1) allows the creation of chained function calls in a readable manner. Basically, the pipeline operator provides syntactic sugar on a function call with a single argument allowing you to write
Example from MDN:
const double = (n) => n * 2; const increment = (n) => n + 1; // without pipeline operator double(increment(double(double(5)))); // 42 // with pipeline operator 5 |> double |> double |> increment |> double; // 42
So that’s pretty cool and makes it really easy to understand how the data flows and transitions from the starting “5” to “42” at the end.
The result is code that is much easier to read and comprehend!
Bringing it All Together
So how does the pipeline operator tie in with our “compose” function above?
I’m glad I asked me because this is how I’d go about it:
First to refactor the compose function in to pipe
const pipe = (...fns) => value => fns.reduce((argument, func) => func(argument), value);
Now for some example usage
const double = number => number * 2; const increment = number => number + 1; const doubleThenIncrement = pipe(double, increment); log( 'Result of doubling then incrementing "4"', doubleThenIncrement(4) );
Now that we have the functionality let’s refactor to use the new pipeline operator
const pipe = (...fns) => value => fns.reduce((argument, func) => argument |> func, value);
Finally, let’s refactor our example
const double = number => number * 2; const increment = number => number + 1; const doubleThenIncrement = pipe(double, increment); log( 'Result of doubling then incrementing "4"', 4 |> doubleThenIncrement );
And there we have it!
A simple upgrade that makes the whole process of doubling then incrementing a number much more readable and the best part is that it gets more and more readable the more you use it (eventually… the whole being at stage 1 thing is really throwing a wrench in our cleaner code works for now ).
Before you go…
If you enjoyed reading this post please share it. You should check out our other publications, you might like them too! We write from time to time about software development, tips and tricks, and how to become a better developer and business person in general. Join us on the journey of constant improvement!