3
votes

Having a background in powershell scripting i first thought it natural to think of function composition in a pipe kind of way. That means the syntax for composition should be fun1 | fun2 | fun3 in a psudocode kind of way. (where fun[i] is the i'th function to apply in order). This order of functions is also what you find in haskell monadic binds. fun1 >>= fun2 >>= fun3.

But in other occasions in haskell, the order of functions is more math'y, such as fun3 . fun2 . fun1, or in the functorial setting fmap fun3 . fmap fun2 . fmap fun1.

I am very much aware that the functions have different signature in the two examples, but it puzzles me that the structure is reversed, still. My workaround is to sometimes define a function mmap = flip (>>=) such that I can write mmap fun3 . mmap fun2 . mmap fun1.

So to the question:

  1. Is there a mmap already defined? What is is called?
  2. Why if bind defined as an operator with arguments in an order that feels backwards?
1
Your mmap is, not surprisingly, =<<. Monadic bind is not analogous to function composition; it is more like function application.chepner
Good point about application/composition chepner. I ended up switching to Kliesli composition (<=<) instead of reverse bind (=<<),LudvigH

1 Answers

7
votes

Is there a mmap already defined? What is is called?

Hoogle is your friend. The type signature of (>>=) is:

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

Hence, you're looking for a function with the type signature:

flip (>>=) :: Monad m => (a -> m b) -> m a -> m b

This is in fact the =<< function. Hence, you can write fun3 =<< fun2 =<< fun1.

Why is bind defined as an operator with arguments in an order that feels backwards?

It's because monadic code looks a lot like imperative code. For example, consider the following:

permute2 :: [a] -> [[a]]
permute2 xs = do
    x  <- xs
    xs <- map return xs
    return (x:xs)

Without the syntactic sugar of do it would be written as:

permute2 :: [a] -> [[a]]
permute2 xs =
    xs >>= \x ->
    map return xs >>= \xs ->
    return (x:xs)

See the similarity? If we used =<< instead it would look like:

permute2 :: [a] -> [[a]]
permute2 xs = (\x -> (\xs -> return (x:xs)) =<< map return xs) =<< xs

Not very readable is it?