A Small Example of Kleisli Arrows

This is a simple example of use of a mysterious beast called a Kleisli arrow.

Again, I will be using scalaz for my incantations as it comes with the necessary potions.

What is the Problem?

You have functions that take a simple type and return higher kinded types like Options or Lists, and you need to compose those functions. You might think you need to get the first result, pattern match on the it, apply it to the second function, repeat. Sounds rather cumbersome.

Kleisli FTW

The intuition is this:

a Kleisli is function composition for Monads.

Hmm, lets try again:

if you have functions that return kinds of things, like Lists, Options, etc,
then you can use a Kleisli to compose those functions.

The Example

object Kleisli extends App {
  import scalaz._
  import Scalaz._
 
  // Some methods that take simple types and return higher-kinded types
  def str(x: Int): Option[String] = Some(x.toString)
  def toInt(x: String): Option[Int] = Some(x.toInt)
  def double(x: Int): Option[Double] = Some(x * 2)
 
  // Lets compose those functions Ye Olde Way
  def oldSchool(i: Int) = 
    for (x <- str(i); 
    	 y <- toInt(x); 
    	 z <- double(y)) 
    yield z
 
  // Kleisli!
  val funky = kleisli(str _) >=> (toInt _) >=> (double _)
 
  println(oldSchool(1)) // Some(2.0)
  println(funky(1))     // Some(2.0)
 
  // Lets use symbols!
  val reallyFunky =(str) >=> (toInt _) >=> (double _)
}

Update
I was asked by bhericher below about composing functions returning different types. Here is a solution but I am not sure if its the best way:

def opt(x: Int): Option[String] = Some(x.toString)
 
def list(x: String) = List(x)
 
// a function to turn an option into a list
def optToList[T](o: Option[T]) = o.toList
 
// now we can compose opt and list using optToList
val multi = (kleisli(opt _) compose (optToList _)) >=> (list _)

Further reading

6 Responses to A Small Example of Kleisli Arrows

  1. bhericher says:

    Nice post!
    But the result is Some(2.0), not Some(1.0)

  2. bhericher says:

    I notice that in your example, the three functions return an Option : is it mandatory for a Kleisli Arrow? Or could we have something like this :

    f : A => M[B]
    g : B => N[C]

    with M and N being different?

    • channing says:

      No, all the functions must return the same kind. But it would not surprise me to find a means of doing this. I’ll ask around.

    • channing says:

      Actually I have found a way and updated the post, but its not particularly elegant.