Functional Programming in JavaScript, Part 3: Introduction to Functors and Monads Thiery MichelSeptember 26, 2018
#functional-programming#js#tutorial

This is part 3 in a series on Functional Programming in javascript

After discovering the Unit and the Monoid, it's time to talk about `Functors` and `Monads`. I know, those words can be frightening. Their definitions are frightening, too:

Functor

A morphism from a source category to a target category which maps objects to objects and arrows to arrows, in such a way as to preserve domains and codomains (of the arrows) as well as composition and identities. How is that supposed to be helpful? Let's forget those awful definitions and start with an example of problem the functor and monad resolve.

Checking Input Properties

Let's say I want to increment a number.

``````const increment = v => v + 1;
const a = 5;
increment(a); // 6``````

Simple, right? But then someone calls the `increment` function with an incorrect argument:

``````increment('5'); // '51'
// or like this
increment({ v: 5 }); // "[object Object]1"``````

So to handle this case, I need to add a type check to the function:

``````const increment = v => {
if (typeof v !== 'number') {
return NaN; // NaN fit our purpose here, we received not a number, so we return just that
}

return v + 1;
};

increment('5'); // NaN
increment({ v: 5 }); // NaN``````

Good. Now, let's say that I need another function to double a number. Again, to be safe I need to repeat the same type check:

``````const double = v => {
if (typeof v !== 'number') {
return NaN;
}

return v * 2;
};``````

In fact each time I manipulate a value, I should do some verifications:

• Is it the right type?
• Is it here?
• Was there an error?

And sometimes, the value is not even readily available, it comes in a callback, or not, maybe we will get an error.

Echanging The Function And Value Roles

What if instead of passing the value to the functions, we passed the functions to the value? Or rather to a placeholder for the value.

I mean, a value already knows some important things about the functions that will be called with it:

• If I am null, there is no need to execute the function.
• If I am not of the correct type, I should skip all functions passed to me.
• If I am an error, I should not execute this function, but I should execute this other one instead.
• If I am asynchronous, I should call this function once I arrive

In short, the value knows best what to do with the function.

This is the basic idea behind a pattern called Functor: a placeholder for a value, so that you pass the function to the value, and not the other way around. We are in functional programming after all: we want to manipulate functions, not values.

Let's write a placeholder for a number value: a NumberBox.

``````const NumberBox = number => ({
applyFunction: fn => NumberBox(fn(number)),
value: number,
});

NumberBox(5).applyFunction(v => v * 2).applyFunction(v => v + 1).value; // 11``````

For now, this code still suffers from the same problem on non-number arguments. So let's enhance the placeholder to check that it holds a numeric value before applying the function.

``````const NumberBox = number => ({
applyFunction: fn => {
if (typeof number !== 'number') {
return NumberBox(NaN);
}
return NumberBox(fn(number))
},
value: number,
});

NumberBox(5).applyFunction(v => v * 2).applyFunction(v => v + 1).value; // 11
NumberBox({ v: 5 }).applyFunction(v => v * 2).applyFunction(v => v + 1).value; // NaN``````

This `applyFunction` method looks a lot like another function that we often use, doesn't it?

``[1,2,3].map(v => v + 1);``

That's right, `Array.map()` works the same: it takes values from an array instead of a box, but it applies the function all the same.

From now on let's rename `applyFunction` to `map`, as we map a function over a value.

``````const NumberBox = number => ({
map: fn => {
if (typeof number !== 'number') {
return NumberBox(NaN);
}
return NumberBox(fn(number))
},
value: number,
});``````

And, just like that, I have created a functor, which is a value placeholder offering a `map` function to execute functions on it.

So to recapitulate, I have a box that holds a value and can apply a function to it thanks to a `map` method. This allows adding custom logic to the function application. This way I manipulate a function, not a value. And with this pattern, I can do a lot more.

Using The Functor Pattern For Type Checking

Let's generalize the `NumberBox` function to handle any type checking, not just numbers. I'll create a `TypeBox` function, that generates a functor based on a test (or predicate, to use a more exact word):

``````const TypeBox = (predicate, defaultValue) => {
const TypePredicate = value => ({
map: fn => predicate(value)
? TypePredicate(fn(value))
: TypePredicate(defaultValue),
value,
});
return TypePredicate;
};``````

So now I can recreate the `NumberBox` by passing a number check as predicate, and `NaN` as default value:

``````const NumberBox = TypeBox(value => typeof value === 'number', NaN);
NumberBox(5).map(v => v * 2).map(v => v + 1).value; // 11
NumberBox({ v: 5 }).map(v => v * 2).map(v => v + 1).value; // NaN``````

I can also create a `StringBox`, a functor for strings:

``````const StringBox = TypeBox(value => typeof value === 'string', null);
StringBox('world').map(v => 'Hello ' + v).map(v => '**' + v + '**').value; // '**Hello, world**'
StringBox({ v: 5 }).map(v => 'Hello ' + v).map(v => '**' + v + '**').value; // null``````

And you can imagine how this applies to all kinds of type checks.

The `map` method has an interesting property: It allows to compose functions. Said otherwise:

``````const double = v => v * 2;
const increment = v => v + 1;
NumberBox(5).map(double).map(increment).value; // 11
// will have the same result as :
NumberBox(5).map(v => increment(double(v))).value; // 11``````

In fact, any `map` implementation must make sure to have this property. In a functional paradigm, we want to compose small functions into more complex ones.

There is another thing that I must make sure of: `map` must not have any side effects. It must only change the functor value, and nothing else. How can I make sure of this? By testing that mapping the identity function (`v => v`) returns the exact same `functor`. This is called the identity law.

``NumberBox(5).map(v => v)) == NumberBox(5)``

I will not check these laws for the other examples, but feel free to check them for yourself.

Maybe Another Example Sometimes, making a function robust isn't about checking the input type, it's about checking that the input exists. Like when a function accesses a property:

``const street = user.address.street;``

To handle the case where `user` or `user.address` are not set, I need to add existence checks:

``const street = user && user.address && user.address.street;``

I can use the functor pattern to handle such cases. The idea is to create a placeholder to hold sometimes a value, and sometimes nothing. Let's call this functor `Maybe`.

``````const isNothing = value => value === null || typeof value === 'undefined';

const Maybe = value => ({
map: fn => isNothing(value) ? Maybe(null) : Maybe(fn(value)),
value,
});``````

Now it's safe to call properties on a non-object:

``````const user = { name: 'Holmes', address: { street: 'Baker Street', number: '221B' } };
Maybe(user).map(u => u.address).map(a => a.street).value; // 'Baker Street'
const homelessUser = { name: 'The Tramp' };
Maybe(homelessUser).map(u => u.address).map(a => a.street).value; // null``````

Tip: Calling the `value` property at the end isn't very natural in functional programming. I can augment the `Maybe` functor with a getter that accepts a default value as argument:

``````const isNothing = value => value === null || typeof value === 'undefined';

const Maybe = value => ({
map: fn => isNothing(value) ? Maybe(null) : Maybe(fn(value)),
getOrElse = defaultValue => isNothing(value) ? defaultValue : value,
});``````

As for accessing object properties, it can get even better using a `get` helper:

``````const get = key => value => value[key];

const getStreet = user => Maybe(user)
.map(get('street'))

getStreet({
name: 'Holmes',
firstname: 'Sherlock',
street: 'Baker Street',
number: '221B'
}
}); // 'Baker Street'

getStreet({
name: 'Moriarty',

Either Right or Wrong

What about error handling? If the function mapped on a functor throws an error, the functor should be able to handle it.

For instance, let's consider the code required to validate a user email. To be precise, I want to validate an email address only if it is given, otherwise, I ignore it and return `null`.

``````const validateEmail = value => {
if (!value.match(/\[email protected]\S+\.\S+/)) {
throw new Error('The given email is invalid');
}
return value;
}

validateEmail('[email protected]'); // '[email protected]'
validateEmail('[email protected]'); // throw Error('The given email is invalid')``````

I'm not fond of that `throw`, because it interrupts the execution flow. What I'd like is a `validateEmail` function that doesn't throw an error, but may return either a value or an error. How to do this with functors?

I need to return a different functor based on a `try/catch`: either a functor that allows me to continue to map, or a functor that would not change its value anymore (if it's an error). I'll call these two functors `Left` and `Right`. The `validateEmail` function would look like the following:

``````const validateEmail = value => {
if (!value.match(/\[email protected]\S+\.\S+/)) {
return Left(new Error('The given email is invalid'));
}
return Right(value);
}``````

The `Left` functor should never change its value anymore, whatever function is passed to its `map`:

``````const Left = value => ({
map: fn => Left(value),
value
});

Left(5).map(v => v * 2).value // 5``````

As for the `Right` functor, it simply applies a function to its value, transparently. You could call it the `Identify` functor, too.

``````const Right = value => ({
map: fn => Right(fn(value)),
value
});

Right(5).map(v => v * 2).value // 10``````

And now I can chain `map` calls on my email value:

``````validateEmail('[email protected]') // valid email, return Right functor
.map(v => 'Email: ' + v)
.value;  // 'Email: [email protected]'
validateEmail('[email protected]') // invalid email, return Left functor
.map(v => 'Email: ' + v)
.value;  // Error('The given email is invalid')``````

The `Left` and `Right` functors form what we call an `Either`.

Catching Errors

The `validateEmail` returns either a result or an error, but doesn't allow me to do something specific in case of an error. For instance, I may want to catch the `Error` and log its `message` property.

I'll add a `catch()` function to both the `Left` and `Right` functors to allow me to do just that:

``````// on a Right, catch() should do nothing
const Right = value => ({
map: fn => Right(fn(value)),
catch: () => Right(value),
value
});
// catch is ignored on a right
Right(5).catch(error => error.message).value // 5

// on a Left, catch() should apply the function, and return a Right to allow further mapping
const Left = value => ({
map: fn => Left(value),
catch: fn => Right(fn(value)),
value
});
Left(new Error('boom')).catch(error => error.message).value // 'boom'``````

For better reusability, I combine these `Left` and `Right` functors into a generic `tryCatch` function:

``````const tryCatch = fn => value => {
try {
return Right(fn(value)); // everything went fine we go right
} catch (error) {
return Left(error); // oops there was an error let's go left.
}
};``````

And now, I can use this new `tryCatch` function to decorate the initial implementation of `validateEmail`, and get either a `Left` or a `Right` functor in return.

``````const validateEmail = tryCatch(value => {
if (!value.match(/\[email protected]\S+\.\S+/)) {
throw new Error('The given email is invalid');
}
return value;
});

validateMail('[email protected]')
.map(v => 'Email: ' + v)
.catch(get('message'))
.value; // 'Email: [email protected]'
validateMail('[email protected]')
.map(v => 'Email: ' + v)
.catch(get('message'))
.value; // 'The given email is invalid'``````

Combining Functors

Now, let's try to validate not an email string, but a user object that maybe has an email. I do not need to validate the email if the user has no email property.

Let's use `Maybe` and combine it with `Either`:

``````const validateUser = user => Maybe(user)
.map(get('email'))
.map(v =>  validateMail(v)
.catch(get('message'))
);

validateUser({
firstName: 'John',
email: '[email protected]',
}); // Maybe(Right('[email protected]'))

validateUser({
firstName: 'John',
email: '[email protected]',
}); // Maybe(Left('The given email is invalid'))

validateUser({
firstName: 'John',
}); // Maybe(null)``````

I always get a `Maybe`, but its value is either a `Left` or a `Right` functor, or even a null value. So in order to get the value, I have to test `Maybe` value to know what to do with it.

``````const validateUserValue = user => {
const result = validateUser(user).value;
if (value === null || typeof value === 'undefined') {
return null
}
return result.value;
}``````

This is bad: all the code I worked so hard to remove is coming back for revenge. You can imagine that it gets worse if I try to combine more functors, ending up with `.value.value.value.value`... How can I handle this crisis?

Chain To The Rescue

I need a method allowing me to extract a value of a functor, even though this value is wrapped inside another functor.

I need a `flatten` method that removes the inner functor, keeping only its value.

``````const Maybe = value => ({
// we could return the value, but then we would sometimes switch functor type.
// This way Maybe.flatten will always return a Maybe
flatten: () => isNothing(value) ? Maybe(null) : Maybe(value.value),
...,
});

const validateUser = user => Maybe(user)
.map(get('email'))
.map(v =>  validateMail(v)
.catch(get('message'))
)
.flatten()
// since now I will always have a simple Maybe, I can use getOrElse to get the value
.getOrElse('The user has no mail');

validateUser({
firstName: 'John',
email: '[email protected]',
}); // '[email protected]'

validateUser({
firstName: 'John',
email: '[email protected]',
}); // 'The given email is invalid'

validateUser({
firstName: 'John',
}); // 'The user has no mail'``````

So now I can call `.getOrElse` and get the value directly. But that's still not ideal. You see, in functional programming, you often need to map and then flatten, or to flatMap for short. But the term "flatMap" describes what the procedure does, not what it is used for. This operation is used to chain functors, so let's call it that: `chain`.

``````const Maybe = value => ({
flatten: () => isNothing(value) ? Maybe(null) : Maybe(value.value),
// using the named function form instead of the fat arrow function
chain(fn) {
return this.map(fn).flatten();
},
...,
});

const validateUser = user => Maybe(user)
.map(get('email'))
.chain(v =>  validateMail(v)
.catch(get('message'))
)
.getOrElse('The user has no mail');

validateUser({
firstName: 'John',
email: '[email protected]',
}); // '[email protected]'

validateUser({
firstName: 'John',
email: '[email protected]',
}); // 'The given email is invalid'

validateUser({
firstName: 'John',
}).value; // 'The user has no mail'``````

Note that the two names are used in functional programming, so `flatMap` == `chain`.

By the way, a functor that can flatten itself with a `chain` method is called a Monad. So `Maybe` is a monad. Not so scary, right?

Like `map`, `chain` must respect a few laws to ensure that monads combine correctly.

• Left identity

``````Monad(x).chain(f) === f(x)
// f being a function returning a monad``````

Chaining a function to a `monad` is the same as passing the value to the function. This ensures that the encompassing `monad` is totally removed by `chain`.

• Right identity

``Monad(x).chain(Monad) === Monad(x)``

Chaining the monad constructor should return the same monad. This ensures that `chain` has no side effect.

• Associativity

``````monad.chain(f).chain(g) == monad.chain(x => f(x).chain(g));
// f and g being functions returning a monad``````

`Chain` must be associative: Using `.chain(f).chain(g)`, is the same as using `.chain(v => f(v).chain(g))`.

This ensures that we can `chain` function that uses `chain` themselves.

Conclusion

You can play with the code of this tutorial in the CodeSandbox below. It uses a slightly modified example: try to understand why it's better than what was explained earlier.

I hope I have demystified functors and monads, and shown how they can be useful. Next time, I will see how we can use monad to handle side effect in a functional way.