## Function Composition#

To understand Kleisli, let’s first take a look at function composition. In Scala if we define these functions:

```
val getNumberFromDb: Unit => Int = _ => 2
val processNumber: Int => Int = num => num * 2
val writeNumberToDb: Int => Boolean = num => true
```

We can pass these functions to each other - this is the concept of higher order functions:

```
val combo1: Unit => Boolean = _ =>
writeNumberToDb(processNumber(getNumberFromDb(())))
```

The nesting here gets a bit unwieldy. We can solve this with function composition, using Scala’s built-in `compose`

infix function:

```
val combo2: Unit => Boolean =
writeNumberToDb compose processNumber compose getNumberFromDb
combo2(()) // true
```

This executes in right-to-left order. `getNumberFromDb`

is executed, then passed to `processNumber`

, then that result is passed to `writeNumberToDb`

.

We can make this easier to reason about by evaluating the composed functions in left-to-right order, using Scala’s built-in `andThen`

infix function:

```
val combo3: Unit => Boolean =
getNumberFromDb andThen processNumber andThen writeNumberToDb
combo3(()) // true
```

This executes in left-to-right order. `getNumberFromDb`

is executed, then passed to `processNumber`

, then that result is passed to `writeNumberToDb`

, the same as before, but this time we can write it in a more sensible order that’s a bit easier to read (unless you find the `compose`

approach easy). Programmer preferences….

## Monads - cats.effect.IO#

The functions we defined above return values directly. But what if we want to add `IO`

from cats effect? For example:

```
val getNumberFromDb: Unit => IO[Int] = _ => IO.pure(2)
val processNumber: Int => IO[Int] = num => IO.pure(num * 2)
val writeNumberToDb: Int => IO[Boolean] = num => IO.pure(true)
```

Note that now the return values are wrapped in `IO`

. What if we wanted to compose these new `IO`

functions together? We can’t. Adding an `IO`

monad to the mix makes composition impossible, because Scala doesn’t understand how to compose contextual functions.

Instead of composition, what many people do in the Scala/Typelevel world is to either use `flatMap`

:

```
val comboFlatMap: Unit => IO[Boolean] = Unit =>
getNumberFromDb(()) flatMap { number =>
processNumber(number) flatMap { processed =>
writeNumberToDb(processed)
}
}
```

…or use for comprehensions:

```
val comboForComp: Unit => IO[Boolean] = Unit =>
for {
number <- getNumberFromDb(())
processed <- processNumber(number)
result <- writeNumberToDb(processed)
} yield result
```

Either way works. It’s worth noting that the for comprehensions approach tends to be preferred over the `flatMap`

approach, because you avoid nesting multiple functions, which can be difficult to read. The benefit of for comprehensions is that each step can be on a separate line without nesting. It’s also worth noting that the Scala compiler actually rewrites for comprehensions in this case to `flatMap`

internally when it compiles the code.

That being said, this is not function composition. For most Scala/Typelevel codebases, I most often see either the `flatMap`

or the for comprehension approach (with for comprehensions being more common and preferred). However, if we want to do this with function composition, while we can’t do that directly with Scala, we can by introducing Kleisli.

## Kleisli#

The type signature for Kleisli is: `Kleisli[F[_], A, B]`

. Kleisli acts as a wrapper around the function `A => F[B]`

. With a Kleisli, if the `F`

has a `flatMap`

defined, we can use it to compose functions of the form `A => F[B]`

. Remember that with typelevel, the `F`

would be `IO`

.

Practically speaking, how do we implement this? Let’s examine our `IO`

functions again:

```
val getNumberFromDb: Unit => IO[Int] = _ => IO.pure(2)
val processNumber: Int => IO[Int] = num => IO.pure(num * 2)
val writeNumberToDb: Int => IO[Boolean] = num => IO.pure(true)
```

I’m going to show two approaches to proper composition of these functions using Kleisli.

### First Form#

```
val getNumberFromDbK: Kleisli[IO, Unit, Int] =
Kleisli(getNumberFromDb)
val processNumberK: Kleisli[IO, Int, Int] =
Kleisli(processNumber)
val writeNumberToDbK: Kleisli[IO, Int, Boolean] =
Kleisli(writeNumberToDb)
```

Note that I’ve defined three new functions, with the same name as the original functions, but appended with a `K`

. I’ve defined these functions as the Kleisli lifted form of the original functions. Meaning I’ve set these new functions equal to the original function, after it’s been passed into the `Kleisli`

constructor.

Note that these functions have the type `Kleisli[F, A, B]`

(the Kleisli signature) where `F`

is replaced with `IO`

, `A`

is the input type of the function, and `B`

is the output type of the function.

Because these new functions are the Kleisli forms of the original functions, they can now be composed together, using `andThen`

, and they will compile and run:

```
val comboKleisli1: Kleisli[IO, Unit, Boolean] =
getNumberFromDbK andThen
processNumberK andThen
writeNumberToDbK
```

### Second Form#

Having to write a new Kleisli function for each of the original `IO`

functions is a bit tedious. Instead of having to do that, cats provides a mechanism for automatically lifting (or wrapping) functions into `Kleisli`

:

```
val comboKleisli2: Kleisli[IO, Unit, Boolean] =
Kleisli(getNumberFromDb) andThen
processNumber andThen
writeNumberToDb
```

The first function in the composition (`getNumberFromDb`

) is lifted, or wrapped, via `Kleisli(getNumberFromDb)`

). By virtue of doing that with the first function and composing with `andThen`

, the remaining two functions don’t require us to wrap in `Kleisli()`

. cats provides implicits so that `andThen`

automatically lifts the rest of the functions in the composition. This means that we don’t have to define three new functions wrapping all the original functions, as we did in the first form. The second form here is a syntactically convenient short-form of Kleisli composition.

## Summary#

Basically the point of Kleisli is to allow us to compose functions that have a context, without worrying about what the context is. And by “context” we mean the `IO`

monad in cats effect, assuming we’re using `cats.effect.IO`

.