Folks,
I'm working on the Haskell 98 report this week, but I'm *still*
not sure what to do about the dreaded MonadZero issue, so this message
has one last go at presenting the issues.
Here are the two proposals I suggested in
http://research.microsoft.com/Users/simonpj
> 1.Fix up the current version.
> use MonadZero for do expressions with *irrefutable* patterns
> (instead of *unfailable* patterns as now)
> 2.Nuke MonadZero altogether.
> add mfail :: m a to Monad instead
John Hughes writes:
> You propose to choose 2. I prefer 1. Why? Apart from categorical niceties,
> 2 is a big change, highly noticeable for many users. Every monad
definition
> that uses MonadZero will have to be rewritten. 1 is much smaller: given
that
> IO is made an instance of class MonadZero, the only programs that will
need to
> change will be those which pattern-match on tuples in a do at a Monad
instance
> not in class MonadZero. Most users won't even notice this.
>
> If 2 were clearly `right in principle' it could be right to do it anyway.
But
> I don't think the principle is clear enough here to justify the suffering.
Erik Meijer also spoke up vigorously in defence of MonadZero. Even though
I proposed (2), I have to admit that (1) is nearer the status quo, and hence
(according to my game plan) the default choice.
But (1) really sticks in my craw. How can we explain this:
f :: Monad m => m (a,b) -> m a
f m1 = do { x <- m1; return (fst x) }
g :: MonadZero m => m (a,b) -> m a
g m1 = do { (a,b) <- m1; return a }
h :: Monad m => m (a,b) -> m a
h m1 = do { ~(a,b) <- m1; return a }
Why must g be in MonadZero? Because the pattern (a,b) is refutable (by
bottom).
In Haskell 1.4 g would not be in MonadZero because (a,b) is unfailable
(it can't fail to match). But the Haskell 1.4 story is unattractive becuase
a) we have to introduce the (new) concept of unfailable
b) if you add an extra constructor to a single-constructor type
then pattern matches on the original constructor suddenly become
failable
But the type differences between g and f,h are really hard to justify.
The 'zero' available in g is never used! Nothing can fail. If we force
'zero' to be available for g, when it can't be used, why not do so for
f and h too?
There seem to be three other alternatives:
3. Make tuples special, so that g would be in Monad, but
if we had a user-defined single-constructor type instead
then it would be in MonadZero
4. Put all 'do' expressions in MonadZero.
5. The status quo
(3) seems dreadful. (4) seems pointless.
The only plausible ones seem (2) [nuke MonadZero] and (5)[status quo].
Comments?
Simon