Best thing about functional programming? If well structured, your programs won’t crash in production. But how can we reach that level of resiliency?
There are a lot of techniques to avoid crashes and unhandled exceptions, but I find the monads to be the greatest way to abstract the possibility of crash/failure inside your codebase.

I am not going to explain what a monad is (it could literally take hours and hours!), but I can show you an incredible and easy way to deal with crashes and exceptions using the Either Monad (No mathematical stuff, I promise!)

What the heck is the Either monad?

Imagine that you’re building a calculator, and you have to implement the division operation (I’ll use typescript because types are extremely important in that case):

function divide(x: number, y: number): number {
  return x / y;
}

pretty easy, isn’t it?
But what would happen if we pass 0 as divisor?

console.log(divide(10, 0));
// => Infinity

What the hell? JavaScript returns Infinity, but other programming languages would crash at this point! We want to return a friendly error message to the user to inform them that it is not possible to divide by zero.
What can we do?

function divide(x: number, y: number): number | string {
  return y === 0
    ? "You can't divide by zero!"
    : x / y
}

this doesn’t seem a great solution… why should a division operation return a string as result? It just makes no sense!
But there is a better alternative!

function divide(x: number, y: number): Either<number, Error> {
  return y === 0
    ? Left(Error("You can't divide by zero!"))
    : Right(x / y)
}

Hey hey hey, what’s happening here?!
Let’s visualize the code above:

We now have a function that may return either an error or a number. But how is it useful?
First of all, the exception won’t be thrown, it will just be encapsulated inside Left and we’ll be able to decide whether to throw it later or just convert it in a more friendly message!
Our code execution won’t stop and we can easily adopt some strategies for handling this exception!

A Practical Example

Ok, now you may want to try it. I’d suggest to use the Sanctuary library, which is an amazing package with a lot of useful methods and monads!
Let’s install it:

npm install --save sanctuary

Great! Now we can import it as follows:

import S from "sanctuary";

interface Either<A, B> {
  constructor: {
    "@@type": "sanctuary/Either"
  }
}

function divide(x: number, y: number): Either<number, Error> {
  return y === 0
    ? S.Left(Error("You can't divide by zero!"))
    : S.Right(x / y)
}

Great! Now let’s try to log some values:

console.log(divide(10, 5));
// => Right (2)

console.log(divide(10, 0));
// => Left (new Error ("You can not divide by zero!"))

Awesome! We now have a wrapped value that won’t cause any interruption to our program.
Let’s make a real world example:

import S from "sanctuary";

interface Either<A, B> {
  constructor: {
    "@@type": "sanctuary/Either"
  }
}

function getUserData(userId: string): Either<string[], Error> {
  try {
    const data: Either<string, Error>[] = await Promise.all([
      getUserName(userId),
      getUserEmail(userId),
      getUserEyeColor(userId)
    ]);

    return data.some(S.isLeft)
      ? S.Left(Error("Ooops. It seems that one promise returned a Left value."))
      : S.Right(data);
  }
  
  catch (error) {
    return S.Left(error);
  }
}

Ok, what’s happening?
We’re spawning three promises concurrently, each of them will return Either<string, error.
Once our promises are resolved, we check if any of them is returning a Left value using the Array.some method. If that is the case, we’ll return a new error wrapped inside Left, otherwise we’ll just return our data.

But once again, what’s so great about that?
As we’ve seen before, our code execution won’t stop even if we get an error or one of the promises get rejected.
But the greatest thing is that if we’re calling the getUserData from another function, we’ll be able to unwrap the values out of the Either monad, and Sanctuary will force us to write a case for both Left and Right values:

...
return S.either (showErrorMessage) (showDataOnFrontend) (getUserData("JSMDY-FPRCKS-X2019"))
...

S.either is a curried function that spawns the first function (showErrorMessage) if the result of the function is Left. Otherwise, it will spawn the second function (showDataOnFrontend).
So, let’s summarize it as follows:

S.either(handleLeftValue)(handleRightValue)(eitherFunction)

Now you may wondering… wtf is this triple-round-parenthesis-expression?
As I said before, this is a curried function, and I think that it can be easier to understand writing it à la Hindley–Milner:

either :: (a -> c) -> (b -> c) -> Either a b -> c

either takes two functions and an Either, and returns the result of applying the first function to the Left's value, if the Either is a Left, or the result of applying the second function to the Right's value, if the Either is a Right. (source

The greatest thing about that function is that it forces you to handle both the cases! So you won’t encounter any kind of unexpected exception runtime.

How do we typically handle these cases without the Either monad?

Now you may wondering: “why should I start to use that monad? I already have my own control structures!”.
Right, but let’s see some cases where Either can be more useful than other control structures:

1) using Promises for rejecting values
You can’t imagine how many times I’ve encountered that kind of code:

function divide(x, y) {
  return new Promise((resolve, reject) => {
    return y === 0
      ? reject("You can't divide by zero!");
      : resolve(x / y);
  });
}

2) Spawning errors
That way you’ll be forced to use a try/catch to avoid a crash. By the way this is a pretty popular way of handling errors, but it could never be as elegant as using the Either monad:

function divide(x, y) {
  return y === 0
    ? new Error("You can't divide by zero!");
    : x / y;
}

3) Returning null/undefined values
That is probably the worst case. null and undefined are probably one of the most error prone parts of any software:

function divide(x, y) {
  return y === 0
    ? null;
    : x / y;
}

Now let’s recap what we’ve seen so far.
The Either monad allows us to handle any kind of exception without letting the program to crash. Our code execution will go on with no problem at all and we’ll be able to decide when and how to show our errors. We’ll also be able to adopt any retry strategy to run a function if it returns a Left value, so… what are you waiting for? Let’s start to use the Either monad!

Did you like this article? Consider becoming a Patron!

This article is CC0 1.0 (Public Domain) licensed.