Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is >>= more often talked about than <=<?

Tags:

haskell

Let's say we have g :: a -> b, and f :: b -> c. We can write:

  1. f . g :: a -> c.

If our functions return monadic values (i.e. values in contexts), for example, g1 :: (Monad m) => a -> m b and f1 :: (Monad m) => b -> m c. We can write:

  1. f1 <=< g1 :: (Monad m) => a -> m c.
  2. return x >>= g1 >>= f1, where x :: a, to get a value back. Or even the lambda \x -> return x >>= g1 >>= f1.

It seems that <=< is more parallel to . in terms of syntax. <=< makes it easier to understand Monad is just about function composition that preserves context. Why is >>= more often talked about than <=<?

like image 247
Jonas Avatar asked Aug 04 '17 18:08

Jonas


1 Answers

<=< is a great way of explaining the monad laws:

 f <=< return = f -- right identity
 return <=< g = g -- left identity
 f <=< (g <=< h) = (f <=< g) <=< h -- associativity

And it's very useful for demonstrating the category of Kleisli arrows:

 newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }
 instance Monad m => Category (Kleisli m) where
   Kleisli f . Kleisli g = Kleisli (f <=< g)
   id = Kleisli return

And you'll see it show up in point-free programs. Personally, I'm also fond of its peer =<<.

But while it makes talking about the monad laws and composition easier, I think there's still some strong didactic reasons that >>= is preferred among monad tutorials and introductions to Haskell.

The first reason being that <=<'s strong suit is point-free code, and for the most part point-free code is harder for people coming from a language in the C-syntax family (C, C++, Java, Python, etc) to understand at first.

If "point-free" is an unfamiliar adjective to you, here's three implementations of the same function:

f a b = a + b * 2
f a = (a +) . (* 2)
f = flip (.) (*2) . (+)

They all run the same calculation, but the last is in what's called point-free style, where the variables on the left have been removed via eta conversion.

This example is very much a strawman, but point-free style is seductive and can easily lead to code that is very difficult for beginners to understand.

Another reason is that one of the near-universal questions beginners ask is "how do I unwrap a IO String to get an String?" when first confronted with Haskell's IO monad. The answer of course is, "you don't, you chain the rest of the computation with >>=", >>= making it easy to explain the relationship between

putStrLn "Your first name: " >>= \_ ->
getLine >>= \first ->
putStrLn "Your last name: " >>= \_ ->
getLine >>= \last ->
putStrLn ("Hello " ++ first ++ " " ++ last)

and

do
  putStrLn "Your first name: "
  first <- getLine
  putStrLn "Your last name: "
  last <- getLine
  putStrLn ("Hello " ++ first ++ " " ++ last)

One last reason, of course, is that >>= is in the definition of Monad, and <=< isn't, and that's just the way the language is defined to be. People are more likely to talk about typeclass members than arbitrary functions when teaching others about the typeclass, especially when the teacher is relatively new to the subject themselves (as so many monad tutorial authors are).

like image 87
rampion Avatar answered Sep 30 '22 17:09

rampion