3

This is a type declaration of a bind method:

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

I read this as follows: apply a function that returns a wrapped value, to a wrapped value.

This method was included to Prelude as part of Monad typeclass. That means there are a lot of cases where it's needed.

OK, but I don't understand why it's a typical solution of a typical case at all.

If you already created a function which returns a wrapped value, why that function doesn't already take a wrapped value?

In other words, what are typical cases where there are many functions which take a normal value, but return a wrapped value? (instead of taking a wrapped value and return a wrapped value)

Mat
  • 202,337
  • 40
  • 393
  • 406
uintptr_t
  • 293
  • 1
  • 3
  • 9
  • Bind is intrinsic to Haskell's monads, which is the way the language handles side effects, among other things. They're also the base of Haskell's do notation. I downvoted your question because there are lots of materials on the web where you can get familiar with these concepts. – Alfonso Villén May 04 '14 at 14:26

8 Answers8

11

The 'unwrapping' of values is exactly what you want to keep hidden when dealing with monads, since it is this that causes a lot of boilerplate.

For example, if you have a sequence of operations which return Maybe values that you want to combine, you have to manually propagate Nothing if you receive one:

nested :: a -> Maybe b
nested x = case f x of
    Nothing -> Nothing
    Just r ->
        case g r of
            Nothing -> Nothing
            Just r' ->
                case h r' of
                    Nothing -> Nothing
                    r'' -> i r''

This is what bind does for you:

Nothing >>= _ = Nothing
Just a >>= f = f a

so you can just write:

nested x = f x >>= g >>= h >>= i

Some monads don't allow you to manually unpack the values at all - the most common example is IO. The only way to get the value from an IO is to map or >>= and both of these require you to propagate IO in the output.

Lee
  • 142,018
  • 20
  • 234
  • 287
3

Everyone focuses on IO monad and inability to "unwrap".

But a Monad is not always a container, so you can't unwrap.

Reader r a == r->a such that (Reader r) is a Monad

to my mind is the simplest best example of a Monad that is not a container.

You can easily write a function that can produce m b given a: a->(r->b). But you can't easily "unwrap" the value from m a, because a is not wrapped in it. Monad is a type-level concept.


Also, notice that if you have m a->m b, you don't have a Monad. What Monad gives you, is a way to build a function m a->m b from a->m b (compare: Functor gives you a way to build a function m a->m b from a->b; ApplicativeFunctor gives you a way to build a function m a->m b from m (a->b))

Sassa NF
  • 5,306
  • 15
  • 22
  • In my mind, `Reader r a` is a container for `a` values indexed by `r` values. A bit like `Map r a`, but the values are computed on the fly. – Toxaris May 03 '14 at 20:18
  • @Toxaris you've just explained the difference between a container and a computation. Also, you can't "index" a value in the `Search b a == (a->b)->a` monad - this would need "indexing" by lambdas. – Sassa NF May 04 '14 at 10:15
2

If you already created a function which returns a wrapped value, why that function doesn't already take a wrapped value?

Because that function would have to unwrap its argument in order to do something with it.

But for many choices of m, you can only unwrap a value if you will eventually rewrap your own result. This idea of "unwrap, do something, then rewrap" is embodied in the (>>=) function which unwraps for you, let's you do something, and forces you to rewrap by the type a -> m b.

To understand why you cannot unwrap without eventually rewrapping, we can look at some examples:

  • If m a = Maybe a, unwrapping for Just x would be easy: just return x. But how can we unwrap Nothing? We cannot. But if we know that we will eventually rewrap, we can skip the "do something" step and return Nothing for the overall operation.

  • If m a = [a], unwrapping for [x] would be easy: just return x. But for unwrapping [], we need the same trick as for Maybe a. And what about unwrapping [x, y, z]? If we know that we will eventually rewrap, we can execute the "do something" three times, for x, y and z and concat the results into a single list.

  • If m a = IO a, no unwrapping is easy because we only know the result sometimes in the future, when we actually run the IO action. But if we know that we will eventually rewrap, we can store the "do something" inside the IO action and perform it later, when we execute the IO action.

I hope these examples make it clear that for many interesting choices of m, we can only implement unwrapping if we know that we are going to rewrap. The type of (>>=) allows precisely this assumption, so it is cleverly chosen to make things work.

Toxaris
  • 7,156
  • 1
  • 21
  • 37
  • 4
    I strongly dislike this "unwrap, do stuff, rewrap" explanation as it isn't just wrong (it's actually impossible), it gives a dangerously incorrect intuition for how monads work. Monad instances can't generally be unwrapped. – Rein Henrichs May 03 '14 at 17:14
  • @ReinHenrichs: My answer is based on the idea that "unwrap is impossible". I show three examples of monads that don't support unwrap and explain why they can't support it. But you seem to have read "unwrap exists" in my answer somehow. Can you suggest how I could clarify? – Toxaris May 03 '14 at 20:20
  • Explaining monads in terms of what some (but not all) monad instances can do lacks the necessary generality and is misleading. It contributes directly to the widespread misconceptions about monads. – Rein Henrichs May 03 '14 at 21:12
  • @ReinHenrichs: The OP didn't ask for an explanation of monads, and my answer doesn't contain one. – Toxaris May 03 '14 at 21:20
  • Fine. Explaining *an aspect of* monads then if you're going to be so pedantic. Using the terms "wrap" and especially "unwrap" anywhere monads are involved is problematic. – Rein Henrichs May 03 '14 at 21:26
2

I will focus on your point

If you already created a function which returns a wrapped value, why that function doesn't already take a wrapped value?

and the IO monad. Suppose you had

getLine :: IO String
putStrLn :: IO String -> IO ()  -- "already takes a wrapped value"

how one could write a program which reads a line and print it twice? An attempt would be

let line = getLine
 in putStrLn line >> putStrLn line

but equational reasoning dictates that this is equivalent to

putStrLn getLine >> putStrLn getLine

which reads two lines instead.

What we lack is a way to "unwrap" the getLine once, and use it twice. The same issue would apply to reading a line, printing "hello", and then printing a line:

let line = getLine in  putStrLn "hello" >> putStrLn line
-- equivalent to
putStrLn "hello" >> putStrLn getLine

So, we also lack a way to specify "when to unwrap" the getLine. The bind >>= operator provides a way to do this.

A more advanced theoretical note

If you swap the arguments around the (>>=) bind operator becomes (=<<)

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

which turns any function f taking an unwrapped value into a function g taking a wrapped value. Such g is known as the Kleisli extension of f. The bind operator guarantees such an extension always exists, and provides a convenient way to use it.

chi
  • 111,837
  • 3
  • 133
  • 218
  • BTW, The `flip`ped version of `>>=` [is actually in the Prelude](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:-61--60--60-). And there's also [`>=>` and `<=<`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Monad.html#v:-62--61--62-), for directly using `a -> m b` functions as composable Kleisli arrows (alternatively, you can use the [`Kleisli` wrapper](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Arrow.html#v:Kleisli)). – leftaroundabout May 03 '14 at 17:50
  • @leftaroundabout Thanks, I included the flipped version in the answer. – chi May 03 '14 at 18:01
  • `(>>= f)` or `(f =<<)` is [the * operation __(f*)__ from the original Moggi's paper](http://stackoverflow.com/a/18290047/849891). – Will Ness May 03 '14 at 18:58
2

While (>>=) can sometimes be useful when used directly, its main purpose is to implement the <- bind syntax in do notation. It has the type m a -> (a -> m b) -> m b mainly because, when used in a do notation block, the right hand side of the <- is of type m a, the left hand side "binds" an a to the given identifier and, when combined with remainder of the do block, is of type a -> m b, the resulting monadic action is of type m b, and this is the only type it possibly could have to make this work.

For example:

echo = do
  input <- getLine
  putStrLn input

The right hand side of the <- is of type IO String

The left hands side of the <- with the remainder of the do block are of type String -> IO (). Compare with the desugared version using >>=:

echo = getLine >>= (\input -> putStrLn input)

The left hand side of the >>= is of type IO String. The right hand side is of type String -> IO (). Now, by applying an eta reduction to the lambda we can instead get:

echo = getLine >>= putStrLn

which shows why >>= is sometimes used directly rather than as the "engine" that powers do notation along with >>.

I'd also like to provide what I think is an important correction to the concept of "unwrapping" a monadic value, which is that it doesn't happen. The Monad class does not provide a generic function of type Monad m => m a -> a. Some particular instances do but this is not a feature of monads in general. Monads, generally speaking, cannot be "unwrapped".

Remember that m >>= k = join (fmap k m) is a law that must be true for any monad. Any particular implementation of >>= must satisfy this law and so must be equivalent to this general implementation.

What this means is that what really happens is that the monadic "computation" a -> m b is "lifted" to become an m a -> m (m b) using fmap and then applied the m a, giving an m (m b); and then join :: m (m a) -> m a is used to squish the two ms together to yield a m b. So the a never gets "out" of the monad. The monad is never "unwrapped". This is an incorrect way to think about monads and I would strongly recommend that you not get in the habit.

Rein Henrichs
  • 15,437
  • 1
  • 45
  • 55
  • about "unwrapping doesn't happen": For most monads, `fmap f p` will pattern match on `p` to extract zero or more non-monadic values, call `f` on them, and then recreate the same structure. This sounds like unwrapping (and rewrapping) to me. – Toxaris May 03 '14 at 20:16
  • That's true of some types that are instances if Monad. It is not true of Monad instances *generally* because it is not something provided by the type class. – Rein Henrichs May 03 '14 at 21:06
  • I believe that my comment about `fmap` is true for all `Functor` instances because of the functor laws. – Toxaris May 03 '14 at 21:25
  • I can't find a way to interpret your comment that would make this true so please tell me why you think so. fmap maps arrows to arrows. It does not provide a way to get an `a` from an `f a`. – Rein Henrichs May 03 '14 at 21:29
  • As I wrote in my first comment above, "`fmap f p` will pattern match on `p` to extract zero or more non-monadic values, call `f` on them, **and then recreate the same structure**". So you are right, `fmap` does not allow you to get the values out of the structure. But you are also wrong, because **in order to call `f`**, `fmap` has to handle such values internally. – Toxaris May 03 '14 at 21:50
  • fmap *might* pattern patch on `p`'s data constructor. This is not always true and is not in any way implied by the laws. Regardless, what some implementations of fmap might do internally are irrelevant to arguments about the behavior of the Functor type class generally, which is defined entirely by the type of fmap and *not* by any specific implementation. They are also irrelevant to arguments about the observable behavior of fmap. – Rein Henrichs May 03 '14 at 22:42
  • I don't understand what you mean by "any specific implementation"? As I understand it, the functor laws uniquely specify how `fmap` behaves for any given datatype. See http://stackoverflow.com/questions/19774904/are-functor-instances-unique. – Toxaris May 04 '14 at 00:30
  • 1
    This is rather confusing. I was responding to *your* argument about the implementations of Functor instances. The instance for `((->) r)` is a counter-example that doesn't (and cannot possibly) pattern match on a data constructor to implement fmap. – Rein Henrichs May 04 '14 at 03:44
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/51968/discussion-between-toxaris-and-rein-henrichs) – Toxaris May 04 '14 at 11:52
1

Because we like to be able to apply functions like a -> b to our m as. Lifting such a function to m a -> m b is trivial (liftM, liftA, >>= return ., fmap) but the opposite is not necessarily possible.

Sarah
  • 6,565
  • 1
  • 33
  • 44
1

You want some typical examples? How about putStrLn :: String -> IO ()? It would make no sense for this function to have the type IO String -> IO () because the origin of the string doesn't matter.

Anyway: You might have the wrong idea because of your "wrapped value" metaphor; I use it myself quite often, but it has its limitations. There isn't necessarily a pure way to get an a out of an m a - for example, if you have a getLine :: IO String, there's not a great deal of interesting things you can do with it - you can put it in a list, chain it in a row and other neat things, but you can't get any useful information out of it because you can't look inside an IO action. What you can do is use >>= which gives you a way to use the result of the action.

Similar things apply to monads where the "wrapping" metaphor applies too; For example the point Maybe monad is to avoid manually wrapping and unwrapping values with and from Just all the time.

Cubic
  • 14,902
  • 5
  • 47
  • 92
1

My two most common examples:

1) I have a series of functions that generate a list of lists, but I finally need a flat list:

f :: a -> [a]

fAppliedThrice :: [a] -> [a]
fAppliedThrice aList = concat (map f (concat (map f (concat (map f a)))))

fAppliedThrice' :: [a] -> [a]
fAppliedThrice' aList = aList >>= f >>= f >>= f

A practical example of using this was when my functions fetched attributes of a foreign key relationship. I could just chain them together to finally obtain a flat list of attributes. Eg: Product hasMany Review hasMany Tag type relationship, and I finally want a list of all the tag names for a product. (I added some template-haskell and got a very good generic attribute fetcher for my purposes).

2) Say you have a series of filter-like functions to apply to some data. And they return Maybe values.

case (val >>= filter >>= filter2 >>= filter3) of
    Nothing -> putStrLn "Bad data"
    Just x -> putStrLn "Good data"
iamnat
  • 4,056
  • 1
  • 23
  • 36
  • The first example isn't nearly as good as you make it out to be. I could just do `iterate (concatMap f) aList !! 3`, which would work better if I iterated a 100 times instead of 3. Although, I suppose your example then becomes `iterate (>>= f) aList !! 3`. But, the argument for `(>>=)` in lists isn't so strong since it is defined to be `concatMap` anyway. – Emil May 03 '14 at 18:01
  • 1
    @user3217013: You're right. I could've been clearer with what I meant. I actually have a definite number (~5) of different functions that need to be applied in series. So it's f1, f2, f3. Also, I had to template them later, so it just read much more naturally than concatMap. – iamnat May 04 '14 at 18:49