Why Either value is not discarded?

Viewed 134

Have the following in ghci:

:m + Control.Monad.Error
let f x = Right x

Left 1.0 >> Right 1 >>= f

gives

Left 1.0

As I understand >> operator discards monadic result of the first argument, but I see that here it is preserved. Could you please explain?

http://hackage.haskell.org/package/base-4.10.0.0/docs/src/Data.Either.html#Either

strangely, that link doesn't show how Either is implementing methods of Monad typeclass.

3 Answers

As I understand[, the] >> operator discards monadic result of the first argument,

No, it does not. It more or less sees Left like a Maybe monad sees Nothing (the main difference is that Left also carries a value). Therefore it is sometimes used as an "advanced Maybe" that can for instance carry error messages.

(>>) :: Monad m => m a -> m b -> m b is a function such that f >> g is equivalent to f >>= \_ -> g and f >>= const g. This is the default implementation in the Monad typeclass.

It depends thus on how (>>=) :: Monad m => m a -> (a -> m b) -> m b is implemented.

Now for an Either it is implemented as:

instance Monad (Either e) where
    Left  l >>= _ = Left l
    Right r >>= k = k r

So that means in case of a Left l on the left hand side, then the right hand side is ignored, in case the left hand side is a Right r, then k is applied to the value the Right constructor is wrapping.

So we can replace your query with (added brackets for clarity):

   Left 1.0 >> Right 1 >>= f
=  (>>) (Left 1.0) (Right 1 >>= f)
-> Left 1.0

Semantically you can see an Either as a "more advanced" version of Maybe where Left takes the place of the Nothing. So from the moment someting is Left x, then it stays Left x. Regardless how we bind it.

Notice the definition contradicts your belief about discarding the left value of a sequence operator:

instance Monad (Either e) where
    Left  l >>= _ = Left l
    Right r >>= k = k r

In fact, in the case of Left the Right value is discarded.

See the source which can be found by clicking on the Monad instance under the Either declaration in the haddocks.

The "result" which is being discarded refers only to the a values contained in (not always literally) an m a value, not the rest of it. In case of Either it means that the value of a Right will be ignored, but not whether it's Left or Right, or the value of a Left.

If you combine the definition of >>= for Either and the default definition of >>, you'll see that >> here is effectively

Left  l >> x = Left  l >>= \_ -> x = Left l
Right r >> x = Right r >>= \_ -> x = x

and the result in the second clause indeed doesn't depend on r.

Related