
On Mon, 2008-10-13 at 18:58 +0100, Andrew Coppin wrote:
Jonathan Cast wrote:
I see... I was under the impression that "mplus" is just any arbitrary binary operation over a given monad. How do you know what it does for a specific monad?
Process of elimination. Sometimes, this doesn't narrow things down to a single operation, but it gives you a good idea of what you're supposed to expect.
Firstly, mplus and mzero form a (natural) monoid, put together. That rules out a number of binary operations right there.
Secondly, mzero has a null law with (>>=):
mzero >>= f = mzero
So, if you have
a `mplus` b
and a calls mzero at some point (not inside another call to mplus --- nice and informal, that description :), then you know b will be executed instead. (Maybe b will be executed *anyway*. I didn't say anything about that).
So mplus and mzero are basically suitable for three kinds of things:
* Exception handling * Back-tracking * Parallelism
Usually, when you see a MonadPlus instance, you expect one or more of these.
That's in the general case.
ListT is a special case; the (somewhat idealized) specification of ListT (what people want to happen when they use ListT) is that ListT m in some sense `adds back-tracking' to m. Where back-tracking choice is implemented by mplus.
Right. OK. So... isn't there a class somewhere called MonadChoice or similar, which defines (<|>)?
It's called Alternative: class Applicative f => Alternative f where empty :: f a (<|>) :: f a -> f a -> fa It's basically MonadPlus, weakened to just applicative functions. (I think that the name (<|>) was probably found after mplus, which is why MonadPlus doesn't use it.) So you can expect, for an arbitrary monad, that the good defintion(s) for mplus and the good definition(s) for (<|
) will coincide.
jcc