# Details

- Reviewers
dfeuer austin ekmett rwbarton CaleGibbard

# Diff Detail

- Repository
- rGHC Glasgow Haskell Compiler
- Branch
- master
- Lint
Lint OK - Unit
No Unit Test Coverage - Build Status
**Buildable 1738**Build 1745: GHC Patch Validation (amd64/Linux)

Let's think this through a bit. The current rules say that `mplus` is associative and `mzero` is its identity, and that

mzero >>= f = mzero v >> mzero = mzero

We're also told that `(<|>)` is associative and has `empty` as its identity, but we're not told anything else about them whatsoever. Ouch. We know that for any `MonadPlus`, we want

mzero = empty mplus = (<|>)

which means the monoid laws for `mzero` and `mplus` follow directly from the ones for `empty` and `(<|>)` and don't necessarily need to be repeated.

The above *suggest* that perhaps we want to require

v *> empty = empty

and also

empty <*> x = empty

And then build the `MonadPlus` laws on top (if there are any left). Are there sane `Alternative` instances that don't obey those rules?

v *> empty = empty

means

(id <$ v) <*> empty = empty

I'm pretty sure this actually implies that for all `v`,

v <*> empty = empty

although I'm not quite certain of that (@ekmett may know). That would give `Alternative` the nice, symmetrical rules

v <*> empty = empty empty <*> v = empty

Intuitively, this seems to make sense: if you apply some functions to no values, or no functions to some values, you get no results.

One thing that's still missing, perhaps, is some kind of "distributive" law relating `<*>` to `<|>`. It feels like there should be something like that to relate the two.

the right unit law doesn't hold.

putStrLn "hello world" <*> empty /= empty

For that matter it is a longstanding issue that this also doesn't hold for:

putStrLn "hello world" `mplus` mzero /= mzero

A discussion of some of the issues with `MonadPlus` can be found in the `MonadPlus` reform proposal on the wiki.

The reform proposal starts with a `MonadZero` class with

mzero >>= k = mzero

This immediately produces two sensible laws for `fmap` and `<*>`:

fmap f empty = empty empty <*> x = empty

The proposed subclasses each add a monoid operation. The one they choose to call `MonadPlus` satisfies a "left distribution" law:

mplus a b >>= k = mplus (a >>= k) (b >>= k)

The "left distribution" law, applied to `Alternative`, looks like this:

(a <|> b) <*> c = (a <|> b) >>= \f -> c >>= \x -> return (f x) = (a >>= \f -> c >>= \x -> return (f x)) <|> (b >>= \f -> c >>= \x -> return (f x)) = (a <*> c) <|> (b <*> c)

which suggests, then, the `Alternative` law

(a <|> b) <*> c = (a <*> c) <|> (b <*> c)

Now `Maybe` doesn't satisfy the left distribution law, but it "morally" satisfies the `Alternative` version:

(Just f <|> b) <*> c = Just f <*> c = case c of {Nothing -> Nothing; Just x -> Just (f x)} (Nothing <|> b) <*> c = b <*> c (Just f <*> c) <|> (b <*> c) = case c of {Nothing -> b `seq` Nothing; Just x -> Just (f x)} (Nothing <*> c) <|> (b <*> c) = Nothing <|> (b <*> c) = b <*> c

The failure of precision there gets much worse with `IO`, unfortunately.

I'm not seeing anything terribly interesting or useful about the alternative "left catch" version, that they call `MonadOr` and that `Maybe` and `IO` fit into naturally.

Actually, `IO` doesn't really fit into *any* of these things very well, does it? Maybe that's why the entire module making it an instance of `MonadPlus` is marked as deprecated. I think we can probably safely document these laws:

fmap f empty = empty empty <*> x = empty

Much more and we'll need a lot more community support. Personally, I love the idea of splitting the class—as it is, `MonadPlus` and `Alternative` mean very little. But that's not my decision.

empty <*> x = empty

doesn't hold. Monad has to inspect the left argument or be trivial because there is no way to see under the lambda in the right hand argument to proceed. However, Applicative is under no such limitation.

>>> import Control.Applicative >>> import Control.Applicative.Backwards >>> import Control.Monad.IO.Class >>> import Control.Monad.List >>> runListT $ forwards (empty <*> Backwards (liftIO $ putStrLn "hello")) hello [] >>> runListT $ forwards empty []

Here I'm not using IO's Alternative, but IO is in the monad transformer stack.

...so, what's the conclusion so far? what laws shall we write into `MonadPlus`'s Haddock docstring?

I think we should get rid of the monoid claim, as it's apparently not true, and write that `<|>` and `mplus` are binary operators that must "do the needful", to borrow a most vague Indian English phrase.

What's the counterexample to MonadPlus being a monoid?

I'm a little confused about the status of the instance MonadPlus IO, but the only problem I see with it being a monoid is that `throwIO SomeFunnyIOException <|> mzero` is `mzero` and not `throwIO SomeFunnyIOException`. But surely the law is closer to being satisfied than not satisfied: the only difference is in which exception is thrown.

Btw, if anyone feels entitled to take the lead, please feel free to commandeer this code-revision and take control. I'm too distracted to be able to follow where this discussion is going... :-)

I'm giving up this one, as at this point I consider `MonadPlus` somewhat obsolete

See also https://prime.haskell.org/ticket/157