[Haskell-cafe] Confusion on the third monad law when using lambda abstractions

Jake McArthur jake.mcarthur at gmail.com
Thu Jun 18 09:34:45 EDT 2009


Hans van Thiel wrote:
> The only place I've ever seen Kleisli composition, or its flip, used is
> in demonstrating the monad laws. Yet it is so elegant and, even having
> its own name, it must have some practical use. Do you, or anybody else,
> have some pointers?

I only just started finding places to use it myself, admittedly, but I 
now think it has common use and it fairly easy to spot. I'll take it 
slow, if not for you, as you seem to have a grasp on what these 
operators are already, then for other readers. Consider a function of 
this form:

     foo x = a $ b $ c $ d $ e $ f x

The obvious thing to do here is to simply drop the `x` from both sides 
by using `(.)` instead of `($)`:

         ==>

     foo x = a . b . c . d . e . f $ x

         ==>

     foo = a . b . c . d . e . f

Now, consider this:

     bar x = a =<< b =<< c =<< d =<< e =<< f x

If you compare that to the original version of `foo` above, you see that 
it is similar. In fact, looking at the types for `($)` and `(=<<)`:

     ($)   ::            (a ->   b) -> (  a ->   b)
     (=<<) :: Monad m => (a -> m b) -> (m a -> m b)

So, `(=<<)` is just like `($)` except for the information carried along 
by the monad.

Anyway, the "obvious" thing to do is to drop the `x` from both sides of 
the definition for `bar`. To do that with `foo` earlier, we had to 
substitute `($)` with `(.)`. What we are looking for is an equivalent 
operator for monads:

     (.)   ::            (b      c) -> (a ->   b) -> (a ->   c)
     (<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)

So we now can do this:

         ==>

     bar x = a <=< b <=< c <=< d <=< e <=< f $ x

         ==>

     bar = a <=< b <=< c <=< d <=< e <=< f

And we're done.

Generally, you can transform anything of the form:

     baz x1 = a =<< b =<< ... =<< z x1

into:

     baz = a <=< b <=< ... <=< z

If you aren't already using `(=<<)` much more than `(>>=)` or 
do-notation then you will have a harder time finding opportunities to 
use `(<=<)` because only `(=<<)` has the same flow as function 
application, which allows your mind to play the appropriate association 
games. I suppose you could also replace `(>>=)` with `(>>>)`, but this 
would likely require more mental adjustment than replacing `(=<<)` with 
`(<=<)`.

- Jake


More information about the Haskell-Cafe mailing list