Toby Hobson

What is a Monad?

banner.png
What is a Monad?
Estimated reading time: 2 minutes

You’re probably already using Monads but you may not realise it. If you’ve called flatMap on an Option or Future you’re playing with Monads. But what exactly are Monads and why do we use them?

In very simple terms a Monad has a map and flatMap method and we use them for sequencing effectful operations e.g. fetch a user based on her id; then fetch the orders associated with this user

What is a Monad?

A Monad is a Functor (it has a map method) but it also has flatten and flatMap methods (flatMap is simply a combination of map and flatten).

Monads must obey certain laws. I don’t believe it’s necessary to fully understand these laws unless you’re writing your own Monads so I won’t go into them here. You can read more on the cats website. At this stage you just need to know that Future, Option, List and Either (Scala 2.12+) can all be thought of as Monads

What do we use Monads for?

We use the flatMap method to sequence effectful operations. In simple terms “effectful” means the operations return monads i.e. Future[String].flatMap(...): Future[A]

For comprehension is often used as syntactic sugar for flatMap calls:

def fetchUser(id: Int): Option[User] = ???
def fetchOrder(user: User): Option[Order] = ???

// <- is just a shortcut for flatMap
for {
  user <- fetchUser(1)
  order <- fetchOrder(user)
} yield (user, order)

We can always compose Functors but not necessarily Monads

What does this mean? It means that so long as we just make use of the map method, we can write generic code that can handle any stack of Functors e.g. List[Option[String]], Option[Future[String]] etc. However the moment we start to use flatMap or flatten we can no longer handle any Monad stack generically.

To understand why this is the case we need to think about structure. In the case of map we’re only changing the innermost type i.e. Future[Option[String]] => Future[Option[Int]] so the only code that needs to be specific is the code to handle this innermost type, maybe parseInt in this example. We don’t need anything specific to Futures and Options (the Functors).

However with flatten or flatMap we’re actually changing the structure of the Monad stack e.g. a flatten call would transform Seq[Option[String]] => Seq[String] so we need something which understands that a None should not be included in the List but a Some should. We call this code a Monad Transformer

What next?

Lean about Monad transformers

comments powered by Disqus

Need help with your project?

Do you need some help or guidance with your project? Reach out to me (email is best)