In his answer to the question “Distinction between typeclasses MonadPlus
, Alternative
, and Monoid
?”, Edward Kmett says that
Moreover, even if
Applicative
was a superclass ofMonad
, you’d wind up needing theMonadPlus
class anyways, because obeyingempty <*> m = empty
isn’t strictly enough to prove that
empty >>= f = empty
So claiming that something is a
MonadPlus
is stronger than claiming it isAlternative
.
It’s clear that any applicative functor which is not a monad is automatically an example of an Alternative
which is not a MonadPlus
, but Edward Kmett’s answer implies that there exists a monad which is an Alternative
but not a MonadPlus
: its empty
and <|>
would satisfy the Alternative
laws,1 but not the MonadPlus
laws.2 I can’t come up with an example of this by myself; does anybody know of one?
1 I wasn’t able to find a canonical reference for a set of Alternative
laws, but I lay out what I believe them to be roughly halfway through my answer to the question “Confused by the meaning of the Alternative
type class and its relationship to other type classes” (search for the phrase “right distributivity”). The four laws I believe ought to hold are:
- Right distributivity (of
<*>
):(f <|> g) <*> a = (f <*> a) <|> (g <*> a)
- Right absorption (for
<*>
):empty <*> a = empty
- Left distributivity (of
fmap
):f <$> (a <|> b) = (f <$> a) <|> (f <$> b)
- Left absorption (for
fmap
):f <$> empty = empty
I’d also happily accept being given a more useful set of Alternative
laws.
2 I know that there’s some ambiguity about what the MonadPlus
laws are; I’m happy with an answer that uses left distribution or left catch, although I would weakly prefer the former.
The clue to your answer is in the HaskellWiki about MonadPlus you linked to:
So according to your favoured choice,
Maybe
isn't a MonadPlus (although there's an instance, it doesn't satisfy left distribution). Let's prove it satisfies Alternative.Maybe
is an Alternative<*>
):(f <|> g) <*> a = (f <*> a) <|> (g <*> a)
Case 1:
f=Nothing
:Case 2:
a=Nothing
:Case 3:
f=Just h, a = Just x
<*>
):empty <*> a = empty
That's easy, because
fmap
):f <$> (a <|> b) = (f <$> a) <|> (f <$> b)
Case 1:
a = Nothing
Case 2:
a = Just x
fmap
):f <$> empty = empty
Another easy one:
Maybe
isn't a MonadPlusLet's prove the assertion that
Maybe
isn't a MonadPlus: We need to show thatmplus a b >>= k = mplus (a >>= k) (b >>= k)
doesn't always hold. The trick is, as ever, to use some binding to sneak very different values out:Now
here I've used bind
(>>=)
to snatch failure (Nothing
) from the jaws of victory becauseJust False
looked like success.Here the failure (
k False
) was calculated early, so got ignored and we"Made it!"
.So,
mplus a b >>= k = Nothing
butmplus (a >>= k) (b >>= k) = Just "Made it!"
.You can look at this as me using
>>=
to break the left-bias ofmplus
forMaybe
.Validity of my proofs:
Just in case you felt I hadn't done enough tedious deriving, I'll prove the identities I used:
Firstly
which come from the instance declaration
Secondly
which just come from
(<$>) = fmap
andThirdly, the other three take a bit more work:
Which comes from the definitions
so
so if
mf
ormx
are Nothing, the result is alsoNothing
, whereas ifmf = Just f
andmx = Just x
, the result isJust (f x)