[Haskell-cafe] Why were unfailable patterns removed and "fail" added to Monad?

Edward Z. Yang ezyang at MIT.EDU
Fri Jan 20 04:19:06 CET 2012


Hello Gregory,

The original (1998!) conversation can be found here:

    http://www.mail-archive.com/haskell@haskell.org/msg03002.html

I think Simon Peyton-Jones' example really sums up the whole issue:

    But [MonadZero] 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 my opinion, the /flexibility/ that was added by mfail was the real
mistake; we should have just had incomplete <- matches be handled the same
way ordinary incomplete pattern matches were accomodated, and figured out
how to nicely allow for multiple patterns in do-notation.  In other words,
MonadZero has no place in dealing with pattern match failure!

But this ship has long sailed.

Cheers,
Edward

Excerpts from Gregory Crosswhite's message of Thu Jan 19 21:47:42 -0500 2012:
> Today I learned (tldr; TIL) that the "fail" in the Monad class was added
> as a hack to deal with the consequences of the decision to remove
> "unfailable" patterns from the language.  I will attempt to describe the
> story as I have picked it up from reading around, but please feel free
> to correct me on the details.  :-)
> 
> An "unfailable" pattern (which is a generalization of an "irrefutable"
> pattern) is a pattern which can never fail (excluding the possibility of
> _|_), such as
> 
>     let (x,y) = pair
> 
> Before "fail" was a method of the Monad class, using refutable patterns
> in a monad required the type to be an instance of MonadZero (that is,
> MonadPlus without the plus), so that for example
> 
>     do Just x <- m
> 
> required that the monad be an instance of MonadZero.  If you avoided
> such patterns, your Monad did not have to have this instance, so that
> for example
> 
>     do (x,y) <- pair
> 
> would not require MonadZero because the pattern is unfailable.
> 
> To me this seems like a lovely way of handling the whole matter, and
> much improved over the incredibly ugly wart of having a "fail" method in
> the Monad class.  In fact, I think I remember people on this list and in
> other forums occasionally bringing something like this approach up as a
> way of getting rid of the "fail" wart.
> 
> So my question is, why did we go to all of the trouble to transition
> away from the MonadZero approach to the current system to begin with? 
> What was so bad about "unfailable" patterns that it was decided to
> remove them and in doing so replace MonadZero with a mandatory "fail"
> method in Monad?  I mean, this *is* Haskell, so my safest assumption is
> that smart people were involved in making this decision and therefore
> the reasons much have been really good (or at least, seemed good given
> the information at the time).  :-)
> 
> Cheers,
> Greg
> 



More information about the Haskell-Cafe mailing list