Advanced FP for the Enterprise Bee: Kleisli
Introduction
This is the fourth article in a series, exploring advanced FP concepts for practically minded Kotlin developers. So far we have looked at Traverse, Applicatives and Higher Kinded Types. This time we are investigating the Kleisli type.
I was very reluctant to go near this concept, mostly because this term is borrowed from Category Theory. So I assumed it would be tortuous. Fortunately it turns out Kleisli is simpler than a lot of the concepts we have already covered.
A Sample Problem
Let’s start by revisiting an only friend from our first article. This function attempts to read a JVM property, returning the result in an Either.
Let’s imagine we need to navigate a chain of property values:
- We are given the key A for a JVM property
- The value of property A will be the key B
- The value of property B will be the key C
- This process must be repeated N times
Let’s create two helper methods, one to create such a chain and the other to print out all the JVM properties:
As sample data let’s use the lineage of House Atreides from the Dune books:
When we run the above the output contains the following information:
Vladimir | Jessica
Jessica | Paul
Paul | Ghanima
Ghanima | Moneo
Moneo | Siona
Our task is to navigate this chain of associations via FP and Arrow.
A Procedural Solution
This is how the problem could be solved in a procedural way:
Running this code produces the correct output:
Right(Siona)
There are three problems with the procedural approach:
- We had to wrap up propertyViaJVM in a new function that takes an Either
- To implement this function we need to be mindful of the rules for Either
- Applying this function requires nesting and/or temporary variables
The Kleisli Solution
Here’s the solution written using the Kleisli type. We still wrap up the propertyViaJVM function, but there are important differences:
- The wrapping is performed for us via
Kleisli { … }
- The wrapped function takes a regular String as input
- The implementation of Either is abstracted from us
We chain together all the required calls using andThen. This composes the calls together into a single sequence, which is executed when we call run. A call to fix is required to perform a downcast, for reasons discussed in the previous article.
If you’re familiar with the CompletableFuture type in the Java threading libraries this is a very similar design. Let’s see how it performs with correct and erroneous data:
It gives us precisely what we want:
Right(Siona)
Left(No JVM property: Alia)
Because we are only wrapping up a single function, we can simplify the code by replacing the lambda with a method reference:
Additional Functionality in Kleisli
So far we have seen that the Kleisli type simplifies the composition of functions, where the functions return, but do not accept, a monadic type like Either or Validated. There are also some helpful utility methods. Let’s modify our input data slightly:
In addition to the existing requirements we now want to:
- Append ‘Harkonnen’ to the initial value given by the client. This ability is provided by the local function.
- Append ‘Atreides’ to the final value produced by the call to run. As you might expect, this ability is provided by the map function.
Once again this gives us the output we wanted:
Right(Siona Atreides)
Left(No JVM property: Alia)
Why Not Use Monads?
When I encountered Kleisli my immediate question was ‘why not just use Monadic Composition?’. It turns out that we always can — and in fact that’s how the Kleisli is implemented.
You may have noticed above that we passed the Either Monad into andThen. Turns out that, if you have already implemented a monadic type, then you get the Kelisli for free. So you can choose whichever approach suits best.
Here’s the problem solved using Monadic Composition directly:
This gives the result we want. But compared to the Kleisli solution there is a lot more ‘plumbing’. We had to remember to:
- Make our functions suspending
- Use the bang operator (or equivalent)
- Declare variables for intermediate results
What Are Kleisli Arrows?
In both Pure Functional Programming and Category Theory the composition of functions is represented by drawing (or coding) arrows. Here’s a superb talk, filled with arrow diagrams, by Philip Wadler. A Kleisli Arrow represents functional composition within a monadic context. In our case the monad was Either, but it could have been Validated, Writer, State etc...
This is why functional libraries, language permitting, often provide an arrow symbol as an alternative to the andThen method. Here’s our example rewritten in Scala and the Scalaz library.
Note how, on line 31, we use the >=> operator to combine the functions:
Conclusions
Despite the term Kleisli originating from Category Theory, it is neither complex nor impractical. Kleisli is a great alternative to Monadic Composition any time you have:
- One or more functions that return a Container (aka. Monad) but take regular parameters.
- A requirement to chain these functions together to obtain a final result.
Running The Sample Code
As usual all the code listed can be found in this BitBucket repo. However the Kleisli type used is still experimental and hence can be found in the Arrow Incubator Project. To run my ‘UsingKleisli’ project you will have to first clone and build arrow-incubator, and then copy the arrow-mtl and arrow-mtl-data libraries into the libs folder.
Thanks
I am grateful to Richard Gibson and the Instil training team for reviews, comments and encouragement on this series of articles. All errors are of course my own.