Understanding Monads: An Introduction

Reading Time: 3 minutes

In Scala, we all have heard about Option, Future etc. I also heard that they are Monads. It was a new term to me so I googled it and the definitions I initially read were too confusing. Here is one of them :

What is Monoid? What are Endofunctors?

Looking into all these is so complex. So here, I’ll try to cover Monads in a much simple way.

What is a Monad?

A monad is a mechanism for sequencing computations.

What does that mean? A monad basically provides you with operations that enable sequencing the computation. By that, we can perform multiple operations one after other and even handle intermediate complications.

A monad has at least these 2 methods:

  • pure of type A => F[A]: This can be considered as a constructor. It can crate monadic context from a plain value.
  • flatMap of type (F[A], A => F[B]) => F[B]: It provides the sequencing step. It extracts the value from a context and generate the next context in the sequence.

Monad Laws

pure and flatMap should obey following laws to avoid side-effecting:

  • Left Identity: calling pure and transforming the result with func is the same as calling func
pure(a).flatMap(func) == func(a)
  • Right Identity: passing pure to flatMap is just like doing nothing
m.flatMap(pure) == m
  • Associativity: flatMapping over two functions f and g is same as flatMapping over f and then flatMapping over g
m.flatMap(f).flatMap(g) == m.flatMap(x => f(x).flatMap(g))

Monad in Cats

In Cats, we have a Monad type class. It’s simplified version looks like the following:

import scala.language.higherKinds
trait Monad[F[_]] {
def pure[A](value: A): F[A]
def flatMap[A, B](value: F[A])(func: A => F[B]): F[B]
}

It also has a map function which is defined in terms of pure and flatmap.

The above type class was just for your reference, for you to know how it is in Cats. But we don’t have to extend it. We will give Monads the Cats treatment i.e we will import type class, instances and syntax and we are ready to go.

Monad Type Class

The Monad Type Class in cats.Monads. By importing that we can use Monad in our code and with that the functions pure, flatMap and Map will be available to us.

Getting Default Instances

Cats provides instances for all the Monads in the standard library(Option, List, Vector etc.) by using cats.instances.

Let’s look at an example here:

import cats.Monad
import cats.instances.option._ 

val opt1 = Monad[Option].pure(5)
// This will create a value of Option type
// opt1: Option[Int] = Some(5)
val opt2 = Monad[Option].flatMap(opt1)(a => Some(a + 2))
// opt2: Option[Int] = Some(7)
val opt3 = Monad[Option].map(opt2)(a => 100 * a)
// opt3: Option[Int] = Some(700)

Monad Syntax

We get Monad syntax by using 3 imports:

  • cats.syntax.flatMap provides syntax for flatMap
  • cats.synax.functor provides syntax for map
  • cats.syntax.applicative provides syntax for pure

Let’s look at an example here:

import cats.Monad
import cats.instances.option._ 
import cats.syntax.applicative._
 //for pure
import cats.syntax.functor._
 //for map
import cats.syntax.flatMap._
 //for flatMap

5.pure[Option]
// res1: Option[Int] = Some(5)
res1.flatMap(a => Some(a + 2))
//res2: Option[Int] = Some(7)
res2.map(a => 100 * a)
//res3: Option[Int] = Some(700)

This was a small introduction to Monads and specifically Monads in Cats. In coming blogs I will discuss many useful Monad Instances that are not covered in Scala standard library. Stay tuned !

Also, if you liked this blog give it a thumbs up and leave your feedback in comment section below.

References

Knoldus-blog-footer-image

Written by 

Muskan Gupta is a Software Consultant having almost 1-year experience. She has knowledge of languages like C, C++, Java and Scala. She is familiar with Object-Oriented Programming Paradigms and also has an interest in relational database technologies. Her hobbies include travelling, reading novels and listening to music.