Desert island code: compose and pipe
You awake a castaway on a desert island. After some time you come across an ancient computation device, the programming of which might hold your salvation!
The device, though limitless in computational power, for better or worse only understands javascript. Alas this dialect of javascript doesn't have access to: compose and pipe!
A cruel fate indeed.
But wait, what if we were to write our own implementations of: pipe and compose?
Pipe
What does pipe do?
Pipe allows left-to-right function composition. The leftmost function may have any arity; but the remaining functions must be unary.
The pipe
function takes a variable number of functions ...fns
and returns a function that takes a single argument which we will call seed
.
const pipe = (...fns) => seed => console.log('do stuff here')
Then, we reduce over the functions ...fns
passing the previous output previousOutput
of each function into the next function until there are no more functions left.
const pipe = (...fns) => seed => fns.reduce(
(previousOutput, fn) => fn(previousOutput),
seed
)
const map = mapFunc => coll => coll.map(mapFunc)
pipe(map(x => x - 2), map(x => x * 2))([1, 2, 3]) // [-2,0,2]
Compose
What does compose do?
Compose allows right-to-left function composition. The rightmost function may have any arity; but the remaining functions must be unary. Basically, the same as pipe just from right-to-left.
The compose
function takes a variable number of functions and returns a function that takes a single argument which we will call seed
.
const compose = (...fns) => seed => console.log('do stuff here')
{% endhighlight %}
Then, we reduce over the functions ...fns
passing the previous output previousOutput
of each function into the next function until there are no more functions left.
const compose = (...fns) => seed => fns.reduceRight(
(previousOutput, fn) => fn(previousOutput),
seed
)
const map = mapFunc => coll => coll.map(mapFunc)
compose(map(x => x - 2), map(x => x * 2))([1, 2, 3]) // [0,2,4]
Bonus: Reduce Right
We saw how to write our own implementation of reduce in this post. But how would we implement reduce right? Reduce right is almost identical to reduce except it loops over the collection backwards.
Here's one way we could implement it:
const reduceRight = (reduceFunc, startingValue, coll) => {
let accumulator = startingValue
for(let i = coll.length - 1; i >= 0; i--) {
accumulator = reduceFunc(accumulator, coll[i])
}
return accumulator
}
reduceRight((acc, item) => acc + item, 0, [ 1, 2, 3, 4]) // 10
So there you have it. Pipe, compose and reduce right on a desert island.