2
$\begingroup$

In Haskell, the Monads type class has the bind operator, which is represented by the symbol >>=

The type of such operator is:

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

Why does the function need to be (a -> m b)? Why functions the preserve che inner data type (a -> m a) are not allowed?

Has this choice been made for some convenience in the language design, or does it have some other reason?

$\endgroup$
2
  • 4
    $\begingroup$ 'a' and 'b' are arbitrary types, and they are allowed to be equal -- this definition is more general than what you are proposing. $\endgroup$ Jun 18, 2014 at 13:22
  • $\begingroup$ Regarding the reason: yes, there are very important mathematical reasons why monads are the way they are. $\endgroup$ Jun 18, 2014 at 13:22

2 Answers 2

4
$\begingroup$

Here's a nice, and accessible, blog on why we need the type to have that form.

http://cdsmith.wordpress.com/2012/04/18/why-do-monads-matter/

Also, this blog motivates why we want them this why and how they naturally arise in our daily workings :)

Enjoy!

$\endgroup$
1
  • 1
    $\begingroup$ Welcome to Computer Science! Your answer consists of little more than a link, which will make it useless, if that link goes dead. Ideally you would recap the most important statements from the linked article explicitly in your post. $\endgroup$
    – FrankW
    Jun 28, 2014 at 7:04
4
$\begingroup$
(>>=) :: Monad m => m a -> (a -> m b) -> m b

Why does the function need to be (a -> m b)? Why functions the preserve che inner data type (a -> m a) are not allowed?

You seem to have missed a basic principle behind type variables: you are allowed to instantiate type variables however you please with concrete types, provided they satisfy the typeclass constraints (here, whatever you choose for m must be a Monad) and are all correctly kinded (m must have kind * -> * and a and b must have kind *).

So if you wanted to instantiate (>>=), some possible choices are:

  • (>>=) :: Monad m => m a -> (a -> m b) -> m b
  • (>>=) :: [a] -> (a -> [b]) -> [b] (instantiating m to [])
  • (>>=) :: Monad m => m a -> (a -> m a) -> m a (instantiating b to a)
  • (>>=) :: Monad m => m b -> (b -> m b) -> m b (instantiating b to a... this is an equal type to the last one).
  • (>>=) :: Maybe Int -> (Int -> Maybe Int) -> Maybe Int
  • (>>=) :: Maybe Char -> (Char -> Maybe Int) -> Maybe Int

One last tidbit that can help understand the "shape" of the types for monad combinators. Look for types of the form a -> m b where m is a monad. These are called Kleisi arrows. If you were fanciful, you might imagine a different syntax for them, like a ~> b meaning "a function from a to b with side effects allowed by some monad m".

Looking at the type of bind, you see a raw m a type at the front. This is essentially the same as () -> m a: a function which takes "no inputs", and produces an a with side effects in m. The m b at the end is similar.

If we rewrite this type in terms of these Kleisi arrows, we get:

(() -> m a) -> (a -> m b) -> (() -> m b)

Rewriting using our 'fanciful' syntax above, it becomes a little clearer:

(() ~> a) -> (a ~> b) -> (() ~> b)

If you squint, this ends up looking like function composition: You start off with (), do something and get to a then do a second thing and get to b. Combining those two steps into one, we just start with () and get to b directly.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.