JavaScript is partly a functional language.
To learn JavaScript, we got to learn the functional parts of JavaScript.
In this article, we’ll look at how to pipe functions and functors with JavaScript.
Pipe
We can create a pipe
function by creating a function that takes an array of functions as arguments.
It returns a function that takes a value and we call reduce
on it with that calls fn
with acc
.
For example, we can write:
const compose = (...fns) =>
(value) =>
fns.reduceRight((acc, fn) => fn(acc), value)
The only difference is that we used reduceRight
instead of reduce
so that we don’t have to call reverse
to apply all the functions.
Composition is Associative
Composition is associative, this means we can rearrange the parentheses of our operations
For instance:
compose(f, compose(g, h)) == compose(compose(f, g), h)
returns true
.
Functors
Functor is a plain object that implements the function map
while running River each value to produce a new object.
A functor is a container that holds some value in it.
For example, we can write:
const Container = function(val) {
this.value = val;
}
to create our container.
Then we can use new
to invoke the Container
constructor:
let foo = new Container(3);
We can create a Container.of
property to add a container to let us return a Container
instance:
const Container = function(val) {
this.value = val;
}
Container.of = function(value) {
return new Container(value);
}
We added the of
static method to return a Container
instance.
The of
method just gives us an alternative to using the new
operator to create the Container
instance.
Then we can create a Container
instance with the of
method:
const nested = Container.of(Container.of(1));
Then we’ll see the nested Container
instances.
Functor Implements Method Called map
Functors implement the map
method.
We can add it as an instance method by adding it to the prototype
property:
const Container = function(val) {
this.value = val;
}
Container.of = function(value) {
return new Container(value);
}
Container.prototype.map = function(fn) {
return Container.of(fn(this.value));
}
Then we can use the map
method after we create a Container
instance.
For instance, we can use it by writing:
const squared = Container.of(3).map(a => a ** 2);
Then squared
is a Container
instance with value
being 9.
We call map
repeatedly to repeat an operation.
So we can write:
const squared = Container.of(3)
.map(square)
.map(square)
.map(square);
Then squared
is a Container
instance with value
being 6561.
Functor is just an object that implements a map
method.
Conclusion
Functors are plain objects that have value.
The object has a map
method.
We can pipe functions to call multiple functions and get the returned value.
Composition is associative, so we can rearrange the parentheses of our operations.