Tuesday, January 28, 2020

Nomad? No, Monad ! (And it has a home)

Without any prejudice, let me start talking about Monads right away. It's one of the least understood and most feared term among programmers (Unless one has spent considerable time in doing functional programming)

What's a Monad anyway?

If I were to define it in one sentence, I'd borrow it :)

"A monad is a monoid in the category of endofunctors"

This is mathematically correct, and makes no sense to a non-starter. So I'll start with simple explanation.

The term Monad comes from the "Category theory" (Wikipedia)

It's one of the most feared as a "complicated concept", but in reality, it's not. Let us start with the three rules which defines any programming construct to be a Monad and I'll explain them in terms of Java (As I come from a Java background and my target audience is people coming from OO background)

1. A type constructor to build up a Monadic type (i.e., A way to construct a Monad, which must be of generic type)
2. Provides a way of wrapping any non-monadic type to a Monadic type
3. Provides a bind (or return) function, which can work on the embedded value and return the same monad with a transformed embedded value.

Well, what do they mean?

Let's take the example of Optional in Java. (Although I personally disagree it's a pure monadic type)
1. As per the first rule, it must be generic, so is Optional (i.e., Optional<Integer>)
2. As per the second rule, it must provide a way of wrapping some non-monadic value into the monadic type (i.e., Optional.of(3))
3. As per the third rule, it must provide a bind function, which can work on the embedded value, transform it and then wrap it in the same monad. That function is map (flatMap to be more accurate).

Optional.of(3).map(value -> value.toString() + "  is transformed")

This example converts an Optional<Integer> into an Optional<String>. The map method works on the embedded value, than on the Optional itself.

How are they useful?
For one from OO background, the closest similarity of a Monad is to a design pattern. Like design patterns, it solves a commonly recurring issue - reduce boilerplate code.

However, the difference from design patterns is that instead of solving one problem, like most of the design patterns do, it is more generic in nature. It can solve a lot of problems where there is boiler plate code. A few examples where Monads have been useful:

1. Operations involving nullable values (where a function can return null or a valid value)
2. Operations that work on each element of a list
3. Operations involving error values (where a function can return an error or a result)
4. Operations that deal with a promise (i.e., async operations)

As you can see, the operations we defined above are completely un-related to each other, and yet, all can be solved using the same theory, i.e., Monads.

Let's look at each of them. As before, I will use examples of Java wherever possible. Unfortunately, Java doesn't have Monads to cater for 3 and 4 above.
Also, Java's list isn't a Monad. However, you can get the same monadic behavior by converting the list into a Stream.

I will use a Java library called vavr to explain the operations where Java falls short.

1. Operations involving nullable values
How many times have we written code similar to the below to deal with nulls in Java?

Consider a POJO named Person.
class Person {
private Name name;...
//Getters and Setters

And a POJO Name:

class Name {
     private String fullName;

    //Getters and Setters

Now, we pass an instance of the Person class to do some operations on it and return a result (And default to some value if any of the null checks fails).

public String getFullName(Person person) {
    if(person != null) {
        Name name = person.getName();
        if(name != null){
           return name.getFullName();
    return "";

Consider we are dealing with five levels of of class instances instead of two and the code, as you would imagine becomes more and more messy.

The solution? Enter Optional in Java. Let's re-write the method using Optionals.

public String getFullName(Person person) {
    return Optional.ofNullable(person).map(Person::getName).map(Name::getFullName).orElse("");

Neat, eh?

So what's going on here? The null check is built into the Optional Monad.

Stay tuned for more:
(To be continued ... )


Author & Editor

Has laoreet percipitur ad. Vide interesset in mei, no his legimus verterem. Et nostrum imperdiet appellantur usu, mnesarchum referrentur id vim.


Post a Comment