Pipe function in JavaScript

Functional programming is the hip-hop word in town, most especially in the JavaScript side of it. In fact, peradventure you do something with React (maybe work with it full-time, part-time, or on some fun projects), it is unarguable that functional programming has been sprinkled everywhere you go.

Similar to most trending or buzz things, functional programming is easy to jump right in. But as one gets one's feet deep into writing functional programs/code, there get to be some point where things get not easy-funny any longer.

One of such is The Problem of Consecutive Functions Operation.

The Problem of Consecutive Functions Operation

In functional programming, one of the laws is "a function has to do a specific thing per time". For example, getSquareRootOf() returns the square root of whatever number is passed to it as an argument.

//ex-1
getSquareRootOf(25) //5

Multiple operations on the number 25 could then be expressed like in ex-2. This is typically what consecutive functions operation is about. Series of operation to be held on a data in consecutive order.

ex-2
getSquareRootOf(25), then multiplyBy3(),and printToConsole() // 15

Existing Solution I: Deep Nesting

One of the ways to write ex-2 in JavaScript is to use the nested functions where the expression is read from right to left.

ex-3
printToConsole(multiplyBy3(getSquareRootOf(25)))

The problem with deep nesting

From when I was writing the expression in ex-3, my eyes and brain were hard at work not to mess the brackets up. Well, the IDE IntelliSense is there for this purpose you might have thought. But have you considered your sibling developer who might not have the IntelliSense or who is just too in a hurry and wants to edit over a terminal?

Whatever one's argument is, deep nesting has a problem of readability.

Since deep nesting won't do, let's give another solution a try.

Existing solution II: Chaining

// ex-4
// params.getSquareRoot().multiplyBy3().printToConsole()

25.getSquareRoot().multiplyBy3().printToConsole() // 25

Chaining solves the problem of readability since it read from left to right, unlike deep nesting. To cap it, no eyes-hand problem with complicated brackets.

The problem with chaining

It can look all nice until you ask the question "where are the methods - (getSquareRoot().multiplyBy3().printToConsole())- coming from?" If you put a number, 25, on the console, does it has the methods getSquareRoot by default?

The answer is nope. Our way around this is to push our methods to the params prototype. This is a big problem because we might have to pass methods that are not needed just so that they are accessible. For example multiplyBy3 in ex-4B.

// ex-4B
49.getSquareRoot().printToConsole() // 7

25.getSquareRoot().multiplyBy3().printToConsole() // 25

The other problem with chaining is it only accepts methods (or parameters that would yet use a method behind the scene). It can't accommodate any other syntax like literals, yield, await, and so on.

Pipe to the rescue.

Pipe solves all the problems with both chaining and nesting, and yet possesses the superpower of both. In short, it is the way to go so much that there is an existing proposal on having a pipe syntax in JavaScript.

It is readable since it is read from left to right and it doesn't mess with the params prototype, unlike chaining.

Until the proposal will be done, there exists already a pipe function that can be used.

// ex-5
pipe(
 getSquareRoot,
 multiplyBy3,
 console.log
)(25)

It is noteworthy to state that some writings consider ex-5 as Flow and not Pipe. The only difference is how the first argument is treated.

// ex-6

//Flow
flow(
 getSquareRoot,
 multiplyBy3,
 console.log
)(25)

// Pipe
pipe(
 25 /**our parameter is the first argument*/,
 getSquareRoot,
 multiplyBy3,
 console.log
)/**notice no second call*/

Since the implications are not so much of a difference and Pipe in ex-5 has more popularity with use, then maybe we might stick to that until JavaScript comes with the official pipe syntax and definition.

Another way and not too common way to write pipe exist too.

ex-7

const pipeSquareMultiplyBy3 = Pipe(
 getSquareRoot,
 multiplyBy3,
 console.log
)
pipeSquareMultiplyBy3(25)

Pipe implementation

// method 1: I personally prefer this
const pipe = (...args)=>(params)=> args.reduce((acc, arg)=>arg(acc), initialValue = params)

// or method 2
const _reduced = (f, g) => (arg) => g(f(arg));
const pipe = (...fns) => fns.reduce(_reduced);

Thanks for reading thus far. I hope this article is short and comprehensive enough to make you a master with Pipe in JavaScript.

Resources