Two years ago when I started looking into the Functional Programming I came across the word ‘Monad’. I really tried hard to understand it but, in vain. After much deliberation, and not to forget the conversations I had with techies, I found that Monad seems to have a very bad reputation-- for being ‘too complicated’, in spite of being one of the most useful and powerful tools in functional programming. A great session by Brian Beckman, Don't fear the Monad really motivated me to get my hands dirty with it.

In this post I will try to resolve the mystery behind Monad but, before going into the Monads lets understand the term Function Composition. In functional world every function is open to collaborate with another function if, the output type of former function is same as the input type of later

For example, suppose we have two functions f and g, as in z=f(y) and y=g(x). Composing them means we first compute y=g(x), and then use y to z=f(y). It could be done using:-

First approach

float x, y, z;

y = g(x);

z = f(y);

Second approach

The steps can be combined if we don't give a name to the intermediate result:

z = f( g(x) );

The first approach is known as Function Chaining, in which the output of first function goes to the input of second function whereas, the second approach is known as Function Composition. Function chaining is also known as function composition in the functional world but, the only difference is function composition uses Combinators to combine different functions.

Functional programmers in particular, are usually not so content to solve a problem in a fragile way by coding a solution directly. They try to create a code which is resistant to damage in the form of changes to requirements. And, to achieve this, they create Combinators-- and its function true to its name--it combines. It may sound silly, but after you've worked with them for a while you'll find them exciting too. Think of it like a blender, you put some juice, fruit, yogurt, and ice all in there together, and it combines them. The result- a pleasant sum of all the ingredients. However, now just try putting those things together in a cup without blending them first like function chaining.

As in the second approach the input type of f wouldn't be a primitive instead, it would be a functional type that means f would be a higher order function which takes function as an input so, here f is nothing but a combinator. for example

public int Alter(int numberToAlter, Func<int,int> functionAsParameter) {

 return functionAsParameter(numberToAlter);

}

here, we could pass any function to Alter as parameter lets say

incrementor = x -> x+1;

Alter(2, incrementor) //3

multiplier = x -> x*2

Alter(2, multiplier) //4

that is how we can try different combinations of function combined with Alter.

What is Monad

Dictionary meaning of a Monad is a single unit but, in functional world Monad is termed as a combinator which combines different functions such that it appears to be a single.

Monad is just a particular style of combinator. It is the key to Functional programming. Imperative programmers mostly ignore it or sometimes even feared of it. When we talk about the monads, the lot of fancy terminology from category theory that gets thrown around. However the concepts of category theory are irrelevant to what winds up being a simple and well understood functional programming concept.

Monad are just like wrapping a value inside a box, unwrapping the value from the box and passing it the function to get the wrapped value

 

But, the question arises why do we need a Monad ?. So, in OOP usually we perform object composition for example, there are two objects called FileReader and DatabaseWriter these two objects combine to get the task (of reading a file from the disk and saving it to the database) done.

Class FileReader {
  File readFile(String filePath) throws exception;
}


Class DatabaseWriter {

  FileReader fileReader;

  boolean readwriteToDB(String file_path) throws exception {

    File file = fileReader.readFile(file_path)
    if (file != null )
    return DB.save(file)
    return false
  }
}

In the above example you can notice we have IO operations, Database calls and Exceptions which are nothing but the side effects in Functional world and Functional programming strongly discourages these type of implementations but, to get the above task (reading a file and writing it to DB) done in functional world, we need some types of combinators that should combine functions in such a way that there would be no impurities introduced and we get our task done. So, Monad is such a combinator which combines functions without impurities.

Lets get into the technical definition of Monad. A monad a set of three things:

  • a parameterized type M<T>

  • a “unit” function T -> M<T>

  • a “bind” operation: M<T> bind T -> M<U> = M<U>

These may seems over complicated, but it is really simple considering an example, Here I will be using Optional Monad defined in Java 8 which is similar to the Maybe Monad we have in Haskell:

  • Parameterized type: Optional<T> : Here, first rule says T could be of any type Integer, String etc.. so it would be Optional<Integer>

  • unit: Optional.of() : Second rule says there should be a function which takes a type and return its Optional for example Optional.of(Integer) returns Optional<Integer>

  • bind: Optional.flatMap() : And the last rule is bind operator(aka flatmap) this is also called as showed operator because of its symbol >>==. The bind operator is called on Monad like Optional<Integer>, it takes function or lambda as an argument like (Integer -> Optional<String>) and returns a Monad which could be of different type like Optional<String> it will get more cleared with an example

How many times have you had to write code like this to avoid a NullPointerException ?

public String getLastFour(Employee employee) {

   if(employee != null) {

       Address address = employee.getPrimaryAddress();

       if(address != null) {

           ZipCode zip = address.getZipCode();

           if(zip != null) {

               return zip.getLastFour()
           }
       }
   }
   throw new FMLException("Missing data");
}

Not only is this kind of code messy and hard to read (and is perhaps a Law of Demeter violation) — but its dangerous. If we forget to check one of these fields for null we could wind up with a NPE.

How can we use Optional in this code to clear up this mess? Well, we can't. To use Optional, we have first to modify the Zipcode, employee, and Address classes so that all their methods return an Optional. Then, we can change our code to:

public String getLastFour(Optional<Employee> employee) {

if (employee.isPresent()) {

 Optional<Adress> address = employee.getPrimaryAddress();

 if (address.isPresent()) {

   Optional<ZipCode> zipcode = address.getZipCode();

   if (zipcode.isPresent()) {

     zip.getLastFour()
   }
}

But this is NOT how Optional is intended to be used, what we are doing is we are wrapping objects(Employee, Address, Zip) in Optional Context and then unwrapping the parameter from the Optional context to check whether it exists or not but, Optional is a Monad it has to do these all wrapping and unwrapping by itself and is intended to be use as such:

public String getLastFour(Optional<Employee> employee) {

   return employee.flatMap(employee -> Optional.of(employee.getPrimaryAddress())) // returns Optional<Address>
     .flatMap(address -> Optional.of(address.getZipCode())) // returns Optional<ZipCode>
     .filter(zip -> zip.getZipCodeLength() >= 4) // returns Optional<ZipCode> or returns Optional.empty()
     .flatMap(zip -> Optional.of(zip.getLastFour())) // / returns Optional<Integer> or returns Optional.empty()
     .orElseThrow(() -> new FMLException("Missing")); // returns Integer or Exception
}

Here we just map a series of functions over our Optional<Employee> and grab our relevant values. The last line, orElseThrow is of particular interest because that’s where we unwrap and get our final value out, or throw an exception

At its heart, the Optional Monad embodies a concept similar to the null object pattern. That is instead of having a null value we encapsulate the behavior we desire of null in an object. In this case this is represented by Optional.empty(). Also, this is how Optional removes the impurity caused due to the null if no condition matches it just returns Optional.empty()

There’s three method calls here, filter, flatMap and orElseThrow. Let’s take a look at what they each do:

1) filter(zip -> zip.getZipCodeLength() >= 4)

Returns another Optional<Zip>. In this case, if our zipcode is less than 4, we’ll be returned Optional.empty(), otherwise, we’ll get the original Zip ie Optional<Zip>.

2) flatMap(zip -> zip.getLastFour())

If our optional is empty map will just give us another empty Optional, otherwise we’ll grab the Optional of our last four digit of zipcode.

3) orElseThrow(() -> new FMLException("Missing))

This is where we’re extracting our value, if we have a value inside our Optional at this time we’ll grab that value which will be a Integer and would be equivalent to calling Optional<Integer>.get(). If however we have an empty optional then we'll have an exception.

Again, lets get into the third rule of Monad i.e bind here it is termed as flatmap. Now it will get more cleared so, the third rule says

 >>== :: M<T> -> (T -> M<U>) -> M<U>

Here, M<T> is Optional<Employee>

(T -> M<U>) is (employee -> Optional.of(employee.getPrimaryAddress()))

M<U> is Optional<Address>

Now we can see how different functions (employee -> Optional<Address>), (address -> Optional<Zip>) and (zip -> Optional<Integer>) get combined using bind (flatmap) and unit(Optional.of()) to get the (employee -> Optional<Integer>) without introducing any impurity(returning null and checking for null)

Conclusion

Also, we’ve condensed our logic into one simple line of code. The power of Monad when used properly has the ability to reduce a lot of clutter inside your code by expressing your logic as filters and transformations on your data.

This is really just scratching the surface of what Monad is and how we can put this to use. However, if you want to know more about the power of Monads, check out languages such as Haskell. For further reading Learn You a Haskell for Great Good is an excellent resource.