3

Checking at Kleisli definition,

in Cats, and Functional and Reactive Domain Modelling

However I'm not yet able to graps the usefulness of it. If we talk about the case of composing Monadic function, as in function that return monad i.e. A => F[B], i don't see what it actually add to simply sequencing a chain of

flatMap[A, B](ma: F[A])(f: A => F[B]): F[B]

Indeed, being able to chain the above is similar to

If you have a function f: A => F[B] and another function g: B => F[C], where F is a monad, then you can compose them to get A => F[C]

What is it that i am not seeing that is the real added value of "Kleisli" ?

MaatDeamon
  • 9,532
  • 9
  • 60
  • 127
  • Take a look to https://stackoverflow.com/questions/61899370/when-should-one-use-a-kleisli – Emiliano Martinez Sep 21 '20 at 11:18
  • 1
    Kleisli arrows are functions that return values in a context and they are composed with Kleisli composition. While `flatmap` is application in a context, Kleisli composition is composition in a context and leads to point-free style code. –  Sep 21 '20 at 12:46
  • Point-free style code ???? – MaatDeamon Sep 21 '20 at 14:08
  • `flatMap` is used to compose _effectual-values_ that a **Monads**, The **Kleisli** `arrow` is used to compose _functions_ that produce _effectual-values_ (that are **Monads**). So it is just about if you want to compose values or functions; i.e. is the same difference that `y = g(f(x))` VS `h = f andThen g` - `y = h(x)`. – Luis Miguel Mejía Suárez Sep 21 '20 at 14:52

2 Answers2

3

Kleisli is simply a name for a function of shape A => F[B].

We could say that flatMap and Kleisli revolve around a similar idea and are tied to similar concepts, but they are not the same thing. Neither one "adds value upon the other one". Here's an example of their connection:

Monad can be defined in several different, but equally powerful ways. One is using unit + flatMap, with its laws defined as:

  • left-identity law:

         unit(x).flatMap(f) == f(x)
    
  • right-identity law:

         m.flatMap(unit) == m
    
  • associativity law:

         m.flatMap(f).flatMap(g) == m.flatMap(x ⇒ f(x).flatMap(g))
    

Another way is using unit + compose, with its laws defined as:

  • left-identity law:

        unit.compose(f) == f
    
  • right-identity law:

         f.compose(unit) == f
    
  • associativity law:

         f.compose(g.compose(h)) == (f.compose(g)).compose(h)
    

In the above definitions, flatMap is the good old flatMap you know:

def flatMap: F[A] => (A => F[B]) => F[B]

and compose is the composition of Kleisli arrows:

def compose: (A => F[B]) => (B => F[C]) => A => F[C]

So basically it's all about terminology. They often pop up in a similar context, but they are not the same. They are simply names for two related, but different things.

slouc
  • 9,508
  • 3
  • 16
  • 41
  • Ah do what you are saying is that Kleisi with Unit is one of the sufficient laws that makes up a monad. In the same way that flap map and unit does. – MaatDeamon Sep 21 '20 at 11:42
  • Almost. Not Kleisli, but composition of Kleislis. So in both cases you take a Kleisli ( A => F[B] ), but in one case you also have F[A] and you flatMap it, and in the other you have another Kleisli and you compose with it. – slouc Sep 21 '20 at 11:48
  • @MaatDeamon BTW you might want to edit your question because you never really quoted the Kleisli definition; you just said "in Cats, and Functional and Reactive Domain Modelling" – slouc Sep 23 '20 at 07:50
2

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.

melston
  • 2,198
  • 22
  • 39
  • Thank you so much for your details explanation. The thing it is not always easy to realize the power that you have in your hands if I may say. So somehow I was trying to see where defining a composed function bring some advantage to sequencing operation on data. Maybe it is just syntactic, make the contract easier for the consumer of the api or something else. That what I was trying to figure out..... anyway valuable answer ! Appreciated – MaatDeamon Sep 22 '20 at 15:14
  • Great addition to my answer! I started from a different angle, by using composition of Kleislis merely as an example of where they are useful, but now you made me realize that it should be the main emphasis and a starting point when explaining them to people. Thanks! :) – slouc Sep 28 '20 at 07:49
  • Heh. We all come at our learning from different backgrounds and perspectives and presenting the information in different ways is often useful. You never know what will help it to 'click' for someone. – melston Sep 28 '20 at 23:31