We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies.

We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies. Less

We use cookies and other tracking technologies... More

# Login or registerto boost this post!

Show some love to the author of this blog by giving their post some rocket fuel π.

# Login or register to start working on this issue!

Engineers who find a new job through Functional Works average a 15% increase in salary π

# Demystifying the Monad in Scala

Sinisa Louc 17 March, 2018 | 14 min read

In my previous post, I mentioned how I decided to write about variance despite (actually, because of) the fact that there are already several dozen articles on the topic. This is a similar situation. I am fully aware that this is just a drop in the sea, but I feel that most of the sea is polluted with complex mathematical explanations involving category theory, boring explanations which just line up one definition after another without providing the gist of things, and by example-driven explanations that wait three whole seconds before they drown you in a bunch of not-so-easily-readable (mostly Haskell) code.

I will not get technical, and by technical I mean mathematical. Stephen Hawking said that he was warned that every equation he puts into βA brief history of timeβ (great book by the way) would halve the sales; I will go by the same principle here. But I will also try not to be too simplistic, and by simplistic I mean vague. We do need to get our hands dirty. Last, but not least, I will not be providing examples as a primary mean of explaining, but more as a supplement to the main explanation.

## Introduction

You can think of monads as wrappers. You just take an object and wrap it with a monad. Itβs like wrapping a present; you take a scarf, a good book or a fancy watch, and wrap it with some shiny paper and a red ribbon. We wrap gifts with shiny paper because they look pretty, and we wrap objects with monads because monads provide us with the following two operations (if you read about monads somewhere and see the term βtwo natural transformationsβ, this is what they are talking about):

• identity (return in Haskell, unit in Scala)
• bind (>>= in Haskell, flatMap in Scala)

Scala doesnβt come with a built-in monad type like Haskell so we will model the monad ourselves. If you take a look at some cool functional programming libraries like Scalaz you will find monads there, along with the rest of the category theory family (functors, applicatives, monoids and so on), but in plain Scala thereβs no such thing out of the box.

We will model a monad with a generic trait that provides methods unit() and flatMap(). We can call it M instead of Monad simply to be more concise. Here it is:

``````trait M[A] {
def flatMap[B](f: A => M[B]): M[B]
}

def unit[A](x: A): M[A]
``````

See, it provides two aforementioned functions, unit and flatMap. Donβt worry about their signatures, what they do for now or why the unit() method is outside the trait body; weβll get to that in a moment.

Now, note one very important thing hereβββthere is a concept of monad (which we just modeled in Scala half a minute ago) and there are concrete monads of flesh and blood which implement those two functions and actually do something (e.g. IO monad). Sometimes people refer to one thing and sometimes the other, so be careful. We will encounter a couple of concrete monads later in this article. You can think of a generic monad as an interface and concrete monads as implementations.

Thereβs one more thing you should pay attention toβββmonads take a type parameter. We didnβt just write M; we wrote M[A]. Type parameter is like a label sticker on our gift wrap, saying what kind of object we have inside (in real life this would ruin the surprise, but in programming we donβt like surprises). So if we want to wrap some object with our monad wrapper, we must parameterize the monad with the type of the underlying object, e.g. M[Int], M[String], M[MyClass] etc.

Now letβs take a closer look at those two functions.

In case you just joined us, let me repeat that monads come with two operations, unit (also known as identity or return) and flatMap (also known as bind). By the way, literature and online sources are rich with all kinds of naming; I merely mentioned most common ones. Wait, I forgot oneβββunit is also often called pure. But donβt worry, itβs always pretty straightforward which function is being referred to, no matter which naming is used. Oh, they also use zero for unit sometimes. All right, letβs move on.

Unit simply performs the wrapping part. So, in case of our gift wrap analogy, we can pass a book to unit() and it will return our book wrapped up in this super cool shiny colorful wrap paper, with a βbookβ label on it. And in case of our monad trait, if we give it a value of type A, it will return a value of type M[A]. Itβs sort of a monad constructor, if you will. It should become clear at this point why we defined the method unit() outside the trait bodyβββbecause we donβt want to invoke it upon the existing monadic object (e.g. myMonad.unit(βmyBookβ)). That wouldnβt make much sense. We want it as a standalone static method (e.g. unit(βmyBookβ)). By passing our book to unit(), we get it back wrapped in a monad.

Now, about the flatMap. You may already be familiar with it; itβs the very same flatMap you can encounter in other places in Scala, such as collections. Hereβs its signature:

``````def flatMap[B](f: (A) => U[B]): U[B]
``````

Letβs say U is a List. It works for various other types, but weβll use List for this example. Now, what flatMap does is that it takes a function with signature A β List[B] and it uses that function to transform the underlying object of type A into a List[B]. This operation is known as map. Since we transformed our underlying A into a List[B], this leaves us with a List[List[B]]. But we did not use ordinary map()βββwe used flatMap(). This means that the job is not done yet; flatMap will now βflattenβ our List[List[B]] into List[B].

Letβs look at a concrete example. If A is Int, and our function f is

``````val f = (i: Int) => List(i - 1, i, i + 1)
``````

then we can flatMap a list of integers with f as follows:

``````val list = List(5, 6, 7)
println(list.flatMap(f))
// prints List(4, 5, 6, 5, 6, 7, 6, 7, 8)
``````

Note that regular map() would take each number i and expand it to a mini-list (predecessor, original number, successor) which would give us the following list of mini-lists: List((4, 5, 6), (5, 6, 7), (6, 7, 8)). FlatMap goes one step further; it flattens that into one long list, resulting in List(4, 5, 6, 5, 6, 7, 6, 7, 8).

Now letβs say that we have some class M with an underlying type A, written as M[A]. If we want to flatMap that isht - I didnβt invent this phrase; try Googling it; we need to provide a function A β M[B]. FlatMap will then use this function to transform our underlying A into M[B], resulting in a M[M[B]], and then it will flatten the whole thing into M[B].

``````            map with A => M[B]                    flatten
M[A]  ------------------------->  M[M[B]]  -----------> M[B]
``````

Notice how flatMap doesnβt require a function A β M[A], but a more flexible one, A β M[B]. So if M is a List and A is an Int, we can feed the flatMap with functions such as Int β List[String], Int β List[MyClass] and so on. It doesnβt have to be Int β List[Int]. For example, we could have defined f as

``````val f = (i: Int) => List("pred=" + (i - 1), "succ=" + (i + 1))
``````

and then we could flatMap a list of integers with it like this:

``````val list = List(5, 6, 7)
println(list.flatMap(f))
// prints List(pred=4, succ=6, pred=5, succ=7, pred=6, succ=8)
``````

FlatMap is way more powerful than map. It gives us the ability to chain operations together, as youβll see in the examples section. Map functionality is just a subset of flatMap functionality. If you want to have map() available in your monad, you can express it using monadβs existing methods flatMap() and unit() like this (note that g is some function Int β Something, not Int β List[Something]):

``````m map g = flatMap(x => unit(g(x)))
``````

On the other hand, if all we had was map and unit, we would not be able to define flatMap because neither one of them has a clue about flattening. Flatten (also known as join in Haskell) is a very important part of the process in our monad machine; if we had a map, but no ability to flatten (and therefore no flatMap), then we would end up with what is known in category theory as functor. Functors are pretty cool too, but monads are the star of our show so letβs not digress.

By the way, if we decompose flatMap into map (fmap) and flatten (join) we will create a completely equivalent and valid definition of the monad, which would then look something like this:

• def unit: A β F[A]
• def map: A β B
• def flatten: F[F[A]] β F[A]

But weβll stick to the flatMap version.

As I said earlier, there is no such thing as monad type class in Scala. But that doesnβt mean there are no monads in Scala. Monad is not a class or a trait; monad is a concept. Every βwrapperβ that provides us with our two beloved operations, unit and flatMap, is essentially a monad (well, itβs not really enough to just provide methods with those names, they, of course, have to follow certain laws, but weβll get to that).

I think we can now finally put the two and two together and realize that List is a monad! Let that sink in. What a plot twist, huh? Itβs like in that movie when you realize that it was him all along. But waitβββthere are others! Set? Monad. Option? Monad. Future? Monad!(*)

OK, itβs a mass conspiracy movie. Monads are everywhere!

(*): There is a slight controversy whether Future really is or isnβt a monad. Since this is a beginners-friendly text, I will just say that it is a monad and call it a day. In case someone from the Future-is-not-a-true-monad camp is reading this, Iβm sure youβll agree that this is not the place for that debate. Perhaps Iβll even write an article on that too someday; I agree that their breaking of some fundamental functional programming principles such as referential transparency should not go unnoticed. But letβs leave that for some other time.

When you look at them up close, you can see that each one indeed has a flatMap method. What about unit? Well, remember that unit is an operation that creates a monad M[A] from an object of type A. This means that a simple apply() serves as a perfectly good unit. So if we have an object called x, hereβs what unit operation looks like in various monads (recall that thereβs syntax sugar that allows us to invoke e.g. List.apply(3) as List(3)):

``````List:             Set:                     Option:                 Future:
------------------------------------------------------------------
List(x)        Set(x)        Some(x) or Option(x)    Future(x)
``````

Also, as I said earlier, there is no actual monad type class in plain Scala. Constructs such as List, Option, Future etc. donβt extend any special Monad trait (it doesnβt exist), which means that they are not obligated to provide us with methods called unit and flatMap. Itβs by observing them and seeing that they have methods unit() and flatMap() with correct signatures and behavior that we can deduct that they are, in fact, monads.

I can hear you say βbut if thereβs no actual unit() method in Scala (since we said that apply() in monadβs companion object serves as unit), what did you mean by saying βreturn in Haskell, unit in Scala? What, unit is a name for a function that doesnβt exist?β Thatβs a good observation, and yes, you are quite right. βUnitβ is merely a convention for referencing monadβs identity operation in Scala. You can create a perfectly good custom monad and call its methods galvanize and dropTheBass instead of unit and flatMap if you wish. As long as they have proper signatures and do what theyβre supposed to, it will conceptually be a monad. But convention is a nice thing, and Scala community embraced the terms flatMap (as seen in List, Option, Future) for the bind operation and unit (by convention implemented as apply()) for the identity operation.

I said, βas long as they have proper signatures and do what theyβre supposed toβ. OK, we covered the signatures part, but we never really specified what it is exactly that these methods have to do. I mean, we discussed how they should behave, but this is not really enough to define their requirements in more concrete terms. This is where monad laws come into play. These laws must be obeyed by unit and flatMap if our monad is to indeed be a true, proper monad.

Since this is a beginner-friendly text, I will not go into too many details about the theory behind the laws or even demonstrating their correctness. For now, itβs important that you know that they exist; itβs OK if you postpone working through them until you get some practice.

So, if we have some basic value x, a monad instance m (holding some value) and functions f and g of type Int β M[Int], we can write the laws as follows:

- left-identity law: unit(x).flatMap(f) == f(x) - right-identity law: m.flatMap(unit) == m - associativity law: m.flatMap(f).flatMap(g) == m.flatMap(x β f(x).flatMap(g))

Alright. So far we have (hopefully) achieved two out of three goals that I aimed for in this article. We explained the concept of a monad and we drew a parallel to some real-life monads in Scala. By the way, in the beginning, I deliberately only mentioned IO-monad as an example of a concrete monad because I wanted to postpone mentioning the others until you had an idea about the general concept. In case youβre wondering what the hell is an IO-monad anyway, itβs a quite complex little thingy used for IO operations in purely functional languages such as Haskell and this is not the time or place to dive deeper into that one.

Time for the third goalβββwhy are monads useful?

In this section, I will show two monads, Option and Future.

Weβre starting with Option. As you probably know, Option is a construct that allows us to avoid null pointers in Scala (in Haskell itβs called Maybe). We use it for things that may or may not have a defined value. If a value is defined, option equals Some(value), and if itβs not defined, it equals None.

Letβs say we have a bunch of users stored in some database. We also have a service that can load a user from that database with a method loadUser(). It takes a name and provides us with an Option[User], because user with that name may or may not exist.

Each user may or may not have a child (for the sake of the example letβs say thereβs a law enforced in the state which allows a maximum of one child). Note that the child is also of type User, so it can have a child too.

Last, but not leastβββwe have a simple function getChild which returns the child for a given user.

``````trait User {
val child: Option[User]
}
object UserService {
def loadUser(name: String): Option[User] = { /** get user **/ }
}
val getChild = (user: User) => user.child
``````

Now letβs say we want to load a user from the database and if he exists we want to see if he has a grandchild. We need to invoke these three functions:

String β Option[User] // load from db User β Option[User] // get child User β Option[User] // get childβs child

And hereβs the code.

``````val result = UserService.loadUser("mike")
.flatMap(getChild)
.flatMap(getChild)
``````

If you didnβt know how to flatMap a monad, you would probably wind up writing a couple of nested if-then-else branches, checking if option is defined. Nothing wrong with that, but this is far more elegant, concise and in the spirit of functional programming.

OK, letβs take a closer look at our βoptional userβ monad. Remember what we learned earlier. Hereβs the analogy.

``````generic monad:
--------------
unit:     A => M[A]
flatMap: (A => M[B]) => M[B]
--------------
unit:     User => Option[User]
flatMap: (User => Option[User]) => Option[User]
``````

By the way, you can also write those functions as in-place lambda functions instead of defining them a priori. Then the code becomes this:

``````val result = UserService.loadUser("mike")
.flatMap(user => user.child)
.flatMap(user => user.child)
``````

or even more concise:

``````val result = UserService.loadUser("mike")
.flatMap(_.child)
.flatMap(_.child)
``````

You can also use a for-comprehension which is basically syntax sugar for mapping, flatMapping and filtering. I donβt want to digress too much so I wonβt explain it here, you can look it up; Iβll just show you the code.

``````val result   =   for      {
usersChild              <- user.child
usersGrandChild  <- usersChild.child
} yield usersGrandChild
``````

If you find all of this a bit confusing, fiddling around with your own code helps a lot. You can create some dummy users, add a basic implementation to UserService.loadUser() so that it returns one of them, make them raise a ton of children and grandchildren and flatMap the living daylights out of them.

Future is a wrapper over some asynchronous operation. Once the future has been completed you can do whatever it is you need to do with its result.

There are two main ways to use a future:

• use future.onComplete() to define a callback that will work with the result of the future (not so cool)
• use future.flatMap() to simply say which operations should be performed on the result once future is complete (cleaner and more powerful since you can return the result of the last operation)

On to our example. We have an online store and customers who have placed thousands of orders. For each customer we must now get his/her order, check which item the order is for, get the corresponding item from the database, make the actual purchase and write the result of purchase operation to log. Letβs see that in code.

``````// needed for Futures to work
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
trait Order
trait Item
trait PurchaseResult
trait LogResult
object OrderService {
}
object ItemService {
}
def purchaseItem(item: Item): Future[PurchaseResult]
def logPurchase(purchaseResult: PurchaseResult): Future[LogResult]
}
``````

By the way, donβt mind stuff like referencing global objects from within functions etc. I know itβs not best practice, but that is completely besides the point here (hmm, perhaps dependency injection could be my next blog post). Also, note that code above doesnβt compile because I left out the implementations of service methods for clarity. Again, if you want to play with the example yourself (and I strongly recommend it), you can easily create mock implementations yourself, e.g. def loadItem(order: Order) = Future(new Item{}).

Now, similarly to the Option example, there are a couple of functions that we will use. Theyβre pretty trivial as each one simply invokes a method from the corresponding service.

``````val loadItem: Order => Future[Item] = {
}
val purchaseItem: Item => Future[PurchaseResult] = {
}

val logPurchase: PurchaseResult => Future[LogResult] = {
}
``````

We need to load the order for a given customer, get the item in question, make the purchase of that item and log the result. Itβs as easy as:

``````val result =
.flatMap(purchaseItem)
.flatMap(logPurchase)
``````

Hereβs the equally nice for-comprehension alternative, using direct service method invocations instead of the functions that were used above:

``````val result =
for {
} yield logResult
``````

Thatβs it. I hope I managed to shed some light on the mystery of monads.

## Conclusion

Monad with his two weapons, unit and flatMap, is a pretty powerful guy. Of course, they are not the solution to all your problems, but thinking in this way (chaining operations and manipulating data using map, flatMap, filter etc., accompanied by other functional programming constructs such as pattern matching) really improves your reasoning about the code and lowers the number of bugs in it. And given the fact that code is much more often read than written, readability and clearness of such code is a big plus. For example, hereβs an excerpt from the code I wrote at work today (I changed the names):

``````itemService.loadItems(order).flatMap {
case Success(items) =>
val updateResults = items.map { item =>
itemService.purchase(item, order.owner)
}
Future.sequence(updateResults)
.map(toPurchaseResults(_))
.map(mergeResults(_))
case RepositoryFailure(failure) =>