In addition to the answer given by slouc, I think it useful to add that I have never really seen the term Kleisli
used without the term composition
appended to it. So, you might say that the real benefit of separating out Kleisli functions is in how they can be composed.
flatMap
isn't a composition of functions. It is, instead, a sequencing of operations on data. But Kleisli composition (like composition of other functions) allows the creation of new functions from other functions following certain rules - as pointed out by slouc.
In Haskell, composition is done with the dot operator. So, if f: A => B
and g: B => C
, you can have:
h = g . f // h: A => C
But if f
and g
are Kleisli functions (f: A => M[B]
and g: B => M[C]
) this doesn't work. This is where Kleisli composition comes in to play. You often see it defined as the 'fish' operator, >=>
, or something similar. Using Kleisli composition you can have:
h = g >=> f // h: A => M[C]
BTW, depending on the language or library, the order of g
and f
in the fish operator may be reversed. But the concept still applies. You are building a new function from two existing functions via composition. You can, later, apply this function to data and have the same result you would have with sequential applications of flatMap
.
One other thing I should probably mention is that since Kleisli functions compose they form a proper category so you will also see the term Kleisli Category
. It isn't all that important to a SW developer but I had to come to grips with it since I saw it often in documentation and blogs so I thought I would pass it on.