# Hands on function composition with monad transformers

When using functional programming languages like Scala, developers spend a lot of their time composing functions and effects. One of the most common ways to express composability is to use monads. However, composing functions that return different monads can become quite messy and, without the right tools, quickly turn into a massive headache. That’s where **Monad Transformers**, which are the main focus of this post, come in handy!

The focus of this post is not to explain monads and their ability to be transformed as there are already dozens of posts that do that (I will reference some of them in the end of this post). The main goal is to show a concrete example of how transformers can help you in situations where the composability of your code becomes entangled. For the sake of keeping the scope of this text sane, you can think of monads as a design pattern that helps function composability. Furthermore, the only two monads I’ll approach in this post are the `Future`

and the `Option`

monads which are commonly used if you’re a Scala developer.

## Composing a simple API

Let’s suppose we’re using a simple API to query a database in a synchronous way:

```
sealed trait Employee {
val id: String
}
final case class EmployeeWithoutDetails(id: String) extends Employee
final case class EmployeeWithDetails(id: String, name: String, city: String, age: Int) extends Employee
case class Company(companyName: String, employees: List[EmployeeWithoutDetails])
trait SyncDBOps {
protected def getDetails(employeeId: String): Option[EmployeeWithDetails]
protected def getCompany(companyName: String): Option[Company]
}
```

From this simple design, the following conclusions are derived:

- An
`Employee`

is either an`EmployeeWithDetails`

or an`EmployeeWithoutDetails`

- A
`Company`

has a name and a list of employees without their details - A
`SyncDBOps`

can fetch a`Company`

by its name and an`EmployeeWithDetails`

by its id.

Suppose we want to create a new software layer on top of this API and expose a single function with the following specification:

- Receives two strings -
`companyName ; employeeId`

- Gets a company using
`companyName`

- Verifies if that company has an employee with id equal to
`employeeId`

- Retrieves the employee’s age using the
`employeeId`

A simple way to do this would be to use `for-comprehensions`

and compose the two API calls:

```
def getEmployeeAge(employeeId: String, companyName: String): Option[Int] = {
for {
company <- getCompany(companyName)
if company.employees map(_.id) contains employeeId
details <- getDetails(employeeId)
} yield details.age
}
```

If any of the two functions we’re calling - `getCompany`

and `getDetails`

- returns a `None`

, the `getEmployeeAge`

function will immediately terminate and return `None`

as well. This code is quite simple and allows us to compose two function calls that return the `Option`

monad in a readable way.

## Raising the bar for function composition

Let’s imagine that in order to try and raise the throughput of our service, we decided to switch our API layer into an asynchronous API that returns `Futures`

. The data API would then change into the following code:

```
trait AsyncDBOps {
protected def getDetails(employeeId: String): Future[Option[EmployeeWithDetails]]
protected def getCompany(companyName: String): Future[Option[Company]]
}
```

We will now try to compose our two API calls and get our employee’s age using `Future`

of `Option`

:

```
def getEmployeeAge(employeeId: String, companyName: String): Future[Option[Int]] = {
for {
companyOpt: Option[Company] <- getCompany(companyName)
company: Company = companyOpt.getOrElse(Company("error", List()))
if company.employees map(_.id) contains employeeId
detailsOpt: Option[EmployeeWithDetails] <- getDetails(employeeId)
} yield detailsOpt map (_.age)
}
```

There are a lot of issues in this code snippet - First of all, we had to add error-case code for the case where the `getCompany`

function returns `Future.successful(None)`

. Secondly, we introduced a dummy `Company`

in case the first function returns `None`

. This dummy is introduced so that our `if-guard`

isn’t only computed when the first `Option`

is `Some`

. This would be a dramatic change in the semantics of our application as we would be getting an employee’s age even if he didn’t exist in the company (the company was returned as `None`

). By adding the dummy company, we now force the `if-guard`

to return false. However, we are forcing the `Future`

monad to fail when it didn’t! Software that uses this function will now have a hard time distinguishing cases where the `companyName`

didn’t exist from cases where the `Future`

**really** failed.

What a nightmare!

## Monad Transformers

It turns out that this a classical problem in functional programming when composing monads. The answer to it is a design construct called **Monad Transformer**. Summing it up - as there are also multiple posts that cover monad transformers in depth - it allows you to compose functions that return two or more monads. Unfortunately, Scala doesn’t come with monad transformers in its standard library. However, there are two functional programming libraries that provide them in Scala: **scalaz** and **cats**. I will be using cats in this post as I found their documentation more detailed than the one provided by scalaz. Now we can change the previous code and start using monad transformers, in particular `OptionT`

, to refactor the code:

```
import cats.data.OptionT
import cats.std.future._
def getEmployeeAge(employeeId: String, companyName: String): Future[Option[Int]] = {
(for {
company <- OptionT(getCompany(companyName))
if company.employees map(_.id) contains employeeId
details <- OptionT(getDetails(employeeId))
} yield details.age).value
}
```

As you can see, this snippet is nearly equal to the one provided in the first example! The only code introduced here is that we’re now calling the apply function from the `OptionT`

monad. The “magic” being done here is that after applying `OptionT(getCompany(companyName))`

we now get a `Company`

. Not a `Future`

, not an `Option`

, a `Company`

, just like the first example! Scala’s `for-comprehension`

automatically calls the `flatMap`

function for the `OptionT`

monad, which is applying the `Future`

monad followed by the `Option`

monad `flatMap`

functions.

With `OptionT`

, if the `Future`

returns `Failure`

or the `Option`

returns `None`

, the function will immediatelly return with that value. Other than the `OptionT`

apply function, only the `.value`

function is called. This function transforms the `OptionT`

monad back into a `Future[Option[Company]]`

. By using `OptionT`

we have removed our biggest issue in the previous example where we were changing the semantics of the application when composing functions that used two monads. You can get more details about the implementation of `OptionT`

and other monad transformers by going to the cats documentation provided at the end of this post.

## More use cases for monad transformation

Monad transformers aren’t only used when composing functions that return two monads in the form `M[F[T]]`

where `M`

and `F`

are distinct monads like in our previous example of `Future[Option[Company]]`

. Suppose the API was changed into the following two functions:

```
trait HybridDBOps {
protected def getDetails(employeeId: String): Future[EmployeeWithDetails]
protected def getCompany(companyName: String): Option[Company]
}
```

This is also a common use case for monad transformers - composing functions that return **different** monads. Let’s implement the `getEmployeeAge`

function using `OptionT`

:

```
def getEmployeeAge(employeeId: String, companyName: String): Future[Option[Int]] = {
(for {
company <- OptionT.fromOption(getCompany(companyName))
if company.employees map(_.id) contains employeeId
details <- OptionT.liftF(getDetails(employeeId))
} yield details.age).value
}
```

The only changes here when compared to the previous example is that we’re now using the `OptionT.fromOption`

function in the first case, and the `OptionT.liftF`

function in the second one. The `fromOption`

function creates an `OptionT`

from an `Option`

monad. It is internally wrapping the return of the `getCompany`

function in a `Future.successful`

call. The `liftF`

function lifts any monad `F`

into an `OptionT`

. Internally, it is calling the `map`

function from the `Future`

monad and wrapping the returned `EmployeeWithDetails`

in a `Some`

. It is important to note that this is just an example and there are more monad transformers like `EitherT`

, `ListT`

, etc, in both cats and scalaz.

## Conclusion

I hope you enjoyed this post and feel like getting started with function composition using multiple monads. The code used for this post is available at E.Near’s Monad Transformers.

Detailed explanations about monads and monad transformation can be found at: