
It's not obvious that this should be turned on by -Wall, since you would also trigger errors on uses like: [ x | Just x <- xs ] T_T But I do think it ought to be an option. Cheers, Edward Excerpts from Michael Snoyman's message of Thu Jan 19 23:52:10 -0500 2012:
On Fri, Jan 20, 2012 at 6:41 AM, Edward Z. Yang
wrote: Aw, that is really suboptimal. Have you filed a bug?
I think it's a feature, not a bug. When dealing with monads that provide nice[1] implementations of `fail`, you can (ab)use this to avoid writing a bunch of case expressions. I remember reading it in one of the first tutorials on Haskell I looked at (four years ago now? you can see how much this bothered me if I still remember that).
I admit that there are some use cases where the current behavior is convenient, but I think we're paying too steep a price. If we got rid of this feature entirely, we could (a) get rid of fail and (b) have the compiler warn us about a bunch of errors at compile time.
But maybe I should file a feature request: provide an extra warning flag (turned on by -Wall) that will warn when you match on a failable pattern. Essentially, I would want:
SomeConstr args <- someAction
to be interpreted as:
temp <- someAction case temp of SomeConstr args ->
Michael
[1] For some people's definition of nice, not mine.
Edward
Excerpts from Michael Snoyman's message of Thu Jan 19 23:29:59 -0500 2012:
On Fri, Jan 20, 2012 at 5:23 AM, Edward Z. Yang
wrote: Oh, I'm sorry! On a closer reading of your message, you're asking not only asking why 'fail' was added to Monad, but why unfailable patterns were removed.
Well, from the message linked:
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
(b) is a real killer: suppose that you want to add a new constructor and fix all of the places where you assumed there was only one constructor. The compiler needs to emit warnings in this case, and not silently transform these into failable patterns handled by MonadZero...
But wait a second... this is exactly the situation we have today! Suppose I write some code:
data MyType = Foo
test myType = do Foo <- myType return ()
As expected, no warnings. But if I change this "unfailable" code above to the following failable version:
data MyType = Foo | Bar
test myType = do Foo <- myType return ()
I *still* get no warnings! We didn't make sure the compiler spits out warnings. Instead, we guaranteed that it *never* will. This has actually been something that bothers me a lot. Whereas everywhere else in my pattern matching code, the compiler can make sure I didn't make some stupid mistake, in do-notation I can suddenly get a runtime error.
My opinion is we should either reinstate the MonadZero constraint, or simply can failable pattern matches.
Michael