bhericher (34) [Avatar] Offline

I don't clearly understand the difference.

Say we have f : A => M[B] and g : B => M[C]

How does Kleisli composition differ from applying f and then flatmap g on the result of f?

Thank you

Debasish Ghosh (111) [Avatar] Offline
It's all a matter of programming at a higher level of abstraction. With Kleisli I can separate the evaluation of the abstraction from the building of it. Consider the following example ..

scala> def f(i: Int) = List(i, 2 * i)
f: (i: Int)List[Int]

scala> def g(j: Int) = List(j * 2, j * 4)
g: (j: Int)List[Int]

I can always do the following ..

scala> f(10).flatMap(g)
res6: List[Int] = List(20, 40, 40, 80)

and evaluate my composed abstraction. Also the above expression gets complicated when you have more functions to compose. However with Kleisli you can do the following ..

scala> import scalaz._
import scalaz._

scala> import Scalaz._
import Scalaz._

scala> import Kleisli._
import Kleisli._

scala> kleisli(f) >=> kleisli(g)
res7: scalaz.Kleisli[List,Int,Int] = Kleisli(<function1>)

Note we have just formed an expression which is the definition of the abstraction that we would like to compose. We can reuse it later and defer the execution of the composed abstraction. Like this ..

res8: List[Int] = List(20, 40, 40, 80)

And the other advantages of using Kleisli is that you can get access to all the combinators that Kleisli offers. It's a very canonical way to compose effectful functions of the form A => M[B] where B is a monad.

Let me know if you need any more information.

bhericher (34) [Avatar] Offline
Thank you for this very detailed explanation.
As usual, I will better understand things with some practice.
It's sincerly a nice book that is very complementary whith the one of Runar and Paul.