Recently I started writing about functional programing in Javascript by talking about what a functor is. Essentialy a functor is:
An object with a map method that can be applied to the values it contains
In this post I used the identity functor as an example because it is extremely simple but I wanted to write about a more practical functor, the maybe.
Maybe?
So isn't one of the beautiful things about functional programming that it is deterministic? Why would we need something called a maybe
? It sounds very unsure of itself. Well the fact that FP is deterministic refers to the fact that for a given input a function has only one output. But we can't guarantee what the input is! Looking back at the Identity
functor and the map
that I used in the last post, this code makes sense and is being used as intended:
const divBy2 = (num) => num/2;
map(divBy2, map(divBy2, Identity(8))); // Gives us 2
But what happens when instead I try and map inc
over a string?
map(divBy2, map(divBy2, Identity('It blows up!'))); //NaN
In this case would we get a program crashing error, no. But how many times have you had to rewrite the logic to check if a value was defined before operating on it? Probably plenty. And certainly we have all run have all seen undefined is not a function
at one point in time. Well that's what Maybe
solves for us. Maybe is a built in validity check. Let's look.
const _Maybe = function(val) {
this.val = val;
}
const Maybe = (val) => new _Maybe(val);
We can set it up and wrap it in a convenient constructor exactly like we did with the identity function. The difference comes from the implementation of map
which Maybe
has.
_Maybe.prototype.map = function(fn) {
return this.val ? Maybe(fn(this.val)) : Maybe(null);
}
This particular implementation just checks that this.val
for is truthy but we could have it use whatever we wanted for the Maybe
. The point is that when we use map
on a maybe it now automatically checks for a valid value on the object and then either applies the function or returns us a null
Maybe
! So now when we try and do something that might actually blow up with an invalid value our program has a way to catch this gracefully and continue.
const reverse = compose(map(reverse), Maybe);
reverse("string"); // Maybe("gnirts")
reverse(undefined); // Maybe(null)