Question

The signature of the >> function in Haskell is this:

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

And the default implementation is:

x >> y = x >>= \_ -> y

By that, I understand that the >> function always returns its right parameter regardless of the value of the left one. The lambda is not even caring what the value of the left parameter (x) is. Then, why is Nothing >> Just 3 equal to Nothing? Shouldn't it just return Just 3, since that is the value of the argument on the right?

I know that any Just value, will return Nothing, when associated with a Nothing, but in this case the Nothing is not even being captured by the lambda. What am I missing?

Bonus question, >>= is called bind. What is >> called?

Thanks.

Was it helpful?

Solution

Because the bind is not even caring what the value of the lambda is!

Just x  >>= f = f x
Nothing >>= _ = Nothing

Note the (Nothing >>=) does not evaluate its second argument.

OTHER TIPS

To really understand what (>>) does in this case you have to look at the definition of (>>=) for Maybe:

(Just x) >>= k      = k x
Nothing  >>= _      = Nothing

Nothing >>= k evaluates to Nothing regardless of what the k function is. In the specific case of (>>), k just happens to be \_ -> y.

By that, I understand that the >> function always returns its right parameter regardless of the value of the left one

This is the source of your confusion!

m >>= f invokes f for values it "finds inside" m, "combining" the results (where what it means for values to be "found inside" a monadic value and what it means to "combine" are monad-specific).

m >> n has to be equivalent to m >>= \_ -> n. So for each value it finds inside m, it will invoke \_ -> n on it. But Nothing in the Maybe monad doesn't have any values "inside" it. So \_ -> n can't ever even be invoked on anything in order to ignore it and return n! So Nothing >>= \_ -> n has to return something that doesn't depend on n, since it has no way of calling the function to obtain n. There also aren't any values of the wrapped type floating around in this context, so the only option available is simply Nothing.

So rather than your intuition for understanding >> being that it ignores the left and returns what's on the right, it's better to think that it takes the "monadic structure" of what's on the left and binds that with the monadic value on the right. "Monadic structure" is a hand-wavey term for "everything that defines a monadic value other than the values inside it".

listA >> listB does the same thing regardless of the particular values in listA, but it matters how many elements are in it. ioA >> ioB does the same thing regardless of what value is produced by executing ioA, but it matters side effects were done to produce it. stateA >> stateB ignores the value produced by stateA, but sends the current state to stateB. And maybeA >> maybeB does the same thing regardless of the particular value inside maybeA, but it matters whether there is a value or not. Note that the list case behaves very similarly to Maybe; if listA is empty then listA >> listB has to be empty too.

As for your bonus question, when I'm reading code to myself (in my head) I tend to pronounce both >>= and >> as "bind"; when I'm looking at the code as well as pronouncing it there's enough non-verbal awareness of the context that this ambiguity doesn't matter. I actually don't know what I would say to talk aloud with someone about >>= and >>; maybe "bind" and "forgetful bind"?

I think there are two ways to explain the choice.

  1. you appeal to the fact that Maybe, unlike IO for instance, has no side effects. Otherwise not evaluating to the second argument would not make sense. In this view, it seems like an arbitrary choice from a logical perspective, though it is certainly more efficient, if possibly unexpected.

  2. you make Nothing represent an error. Then an error in the first argument would obviate the need to evaluate the second argument. It seems like this is the justification chosen by the authors:

http://hackage.haskell.org/package/base-4.7.0.0/docs/src/Data-Maybe.html#Maybe

-- The 'Maybe' type is also a monad.  It is a simple kind of error
-- monad, where all errors are represented by 'Nothing'.

There are a couple of things I'd like to add to other good answers.

  1. The reason Nothing >>= f has to be Nothing is because it's impossible to check whether f actually uses its argument (without horrible unsafe hacks, at least).

  2. x >> y = x >>= \_ -> y is not merely the default implementation. The definition of >> should always produce the same result as this one. It's only allowed to be overloaded because it can sometimes be implemented more efficiently.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top