We’re starting a new Scala area. If you have a few years of experience in the Scala ecosystem, and you’re interested in sharing that experience with the community, have a look at our **Contribution Guidelines**.

# Monads in Scala

Last modified: September 9, 2021

## 1. Overview

As developers, we often encounter the need to encapsulate values with some additional context that cannot be directly related to the business domain. For example, we often need a value to be in a sequence or computed asynchronously.

Monads are the mechanism we can use to fulfill such needs. Let’s understand them by looking at some examples.

## 2. What Is a Monad?

**Monads are nothing more than a mechanism to sequence computations around values augmented with some additional feature**. The concept of monads comes directly from mathematics, precisely from category theory. For this reason, it’s often considered a tough topic. However, we’re going to make it as easy as possible.

As we said, a monad augments a value with some additional features. **Such features are called effects**. Some well-known effects are managing the nullability of a variable or managing the asynchronicity of its computation. In Scala, the corresponding monads to these effects are the *Option[T] *type and the *Future[T]* type.

As we can see, both types – *Option* and *Future* – define a type parameter. In fact, **a monad adds an effect to a value wrapping it around a context**. In Scala, one way to implement a monad is to use a parametric class on the type.

For example, let’s try to add to values of a generic type *T* the effect of laziness using monads. Hence, we define the *Lazy[A]* class as:

```
class Lazy[+A](value: => A) {
private lazy val internal: A = value
}
```

The *Lazy* type wraps a value of type *A*, provided by a “call-by-name” parameter to the class constructor to avoid eager evaluation.

### 2.1. Wrapping Values Inside a Monad: the *Unit* Function

First, **monads must provide a function that allows wrapping a generic value with the monad’s context**. We usually call such a function *unit*. It’s said that the *unit* function lifts the value in the monadic context. In Scala, we can use the *apply *method of a companion object to implement the *unit* function:

```
object Lazy {
def apply[A](value: => A): Lazy[A] = new Lazy(value)
}
```

In our example, the use of the *unit* function allows us to add the effect of the lazy initialization to a value, wrapping it inside the *Lazy* context:

```
val lazyInt: Lazy[Int] = Lazy {
println("The response to everything is 42")
42
}
```

Hence, the above code doesn’t print anything once executed because its execution’s laziness is lifted to monadic value.

### 2.2. Sequencing Computations Over a Value: the *flatmap* Function

However, the sole capability to add an effect to a monad isn’t worth the complexity added to the code. Moreover, we don’t want to extract the monad’s wrapped value to apply functions to it. It’s cumbersome and unmaintainable. **We need a mechanism to sequence computations over a value wrapped inside a monad**.

To overcome this problem, monads must provide the *flatMap* function. This function takes as input another function from the value of the type wrapped by the monad to the same monad applied to another type:

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

It transforms the value inside a monad into another value without performing any extraction to make it simpler. Hence, if we need to transform the *lazyInt *value into a *String*, we can use the *flatMap* function:

```
val lazyString42: Lazy[String] = lazyInt.flatMap { intValue =>
Lazy(intValue.toString)
}
```

Once again, no string will be printed to the standard output because of all the computation’s laziness. Moreover, we changed the value inside the monad without extracting it. So, any chain of *flatMap* invocation lets us make any sequence of transformations to the wrapped value.

### 2.3. Make It More Imperative: Using the For-comprehension

Last, but not least, we can define the *map* function for any monad in terms of the *flatMap* function:

`def map[B](f: A => B): Lazy[B] = flatMap(x => Lazy(f(x)))`

Why should we do that? Because for any type providing both the *map* and the *flatMap* functions in Scala, we can use the for-comprehension construct (see the article A Comprehensive Guide to For-Comprehension in Scala for further details). **The for-comprehension is quite useful for concatenating computations on the same monad**:

```
val result: Lazy[Int] = for {
first <- Lazy(1)
second <- Lazy(2)
third <- Lazy(3)
} yield first + second + third
```

As we can see, the above code is straightforward to read and lets us use the functional programming and monads in Scala as if we were coding using an imperative style.

For the sake of completeness, the above for-comprehension translates to calling the following sequence of functions:

```
val anotherResult: Lazy[Int] =
Lazy(1).flatMap { first =>
Lazy(2).flatMap { second =>
Lazy(3).map { third =>
first + second + third
}
}
}
```

It’s a terrific improvement, isn’t it?

## 3. The Awful Three: Monads’ Laws

However, with great power comes great responsibility. In fact, it’s not sufficient to add the *unit* and the *flatMap* functions to a type to make it a monad. The complex part comes with the mathematical laws the monad must fulfill.

The three monad laws are:

- Left identity
- Right identity
- Associativity

If the monad satisfies the three laws, then we guarantee that any sequence of applications of the *unit* and the *flatMap* functions leads to a valid monad — in other words, the monad’s effect to a value still holds.

**Monads and their laws define a design pattern from a programming perspective**, a truly reusable code resolving a generic problem.

Let’s describe them one by one.

### 3.1. Left Identity

The first of the three laws, called “left identity”, says that applying a function *f* using the *flatMap* function to a value *x* lifted by the *unit* function is equivalent to applying the function *f* directly to the value *x*:

`Monad.unit(x).flatMap(f) = f(x)`

If we take our *Lazy* monad, we have to prove that the following holds:

`Lazy(x).flatMap(f) == f(x)`

Hence, we can substitute *flatMap(f)* with *f(x)*, so the property holds by definition.

### 3.2. Right Identity

The second monadic law is called “right identity”. It states that application of the *flatMap *function using the *unit *function as the function *f* results in the original monadic value:

`x.flatMap(y => Monad.unit(y)) = x`

It’s easy to prove that our *Lazy* monad also fulfills this law:

`Lazy(x).flatMap(y => Lazy(y)) == Lazy(x)`

As we can substitute the term *flatMap(y => Lazy(y)) * with the result of the application, *Lazy(x)*, the property holds by definition.

### 3.3. Associativity

The last of the three monadic laws is the hardest to deal with and is called “associativity”. This law says that applying two functions *f *and* g *to a monad value using a sequence of *flatMap* calls is equivalent to applying *g* to the result of the application of the *flatMap* function using *f *as the parameter:

`x.flatMap(f).flatMap(g) = o.flatMap(x => f(x).flapMap(g))`

Hence, for the *Lazy *monad, the above rule becomes:

`Lazy(x).flatMap(f).flatMap(g) == f(x).flatMap(g)`

If we apply the substitution derived from the”left identity” law to the terms *Lazy(x).flatMap(f) *of the right side of the equation, we obtain exactly *f(x).flatMap(g)*. So, the associativity rule also holds for our monad 🙂

## 4. Bonus Methods

Until now, we presented the minimum set of methods that a monad must implement to adhere to the pattern. However, we can define many other methods to improve the usability of the *Lazy* type.

For example, we can implement the *flatten *function that removes a level of abstraction in nested monads’ types:

`def flatten(m: Lazy[Lazy[A]]): Lazy[A] = m.flatMap(x => x)`

Moreover, another interesting function to implement is the one that extracts the value contained in the monad. We can call it *get*:

`def get: A = internal`

When we call the *get* function, the lazy value is finally evaluated, performing any effect previously enclosed in the monad.

## 5. Conclusion

In this article, we introduced the concept of monads in Scala. We began by giving a simple definition of monads, and then we introduced the minimum set of functions that a monad must implement: the *unit* and the *flatMap*. Finally, we spoke about the three monad laws.

Finally, monads are a fascinating and useful concept that pervades many types in the Scala standard library. *Option*, *Future*, *Either*, and more or less all the collection types such as *List*, *Tree*, and *Map*, to name a few, are monads.

As always, the full source code of the article is available over on GitHub.