[Haskell-cafe] Why were unfailable patterns removed and "fail" added to Monad?
mokus at deepbondi.net
Fri Jan 20 13:25:41 CET 2012
On Jan 20, 2012, at 1:40 AM, Michael Snoyman wrote:
> On Jan 20, 2012 8:31 AM, "John Meacham" <john at repetae.net> wrote:
> > > 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 is actually the right useful behavior. using things like
> > do
> > Just x <- xs
> > Just y <- ys
> > return (x,y)
> > will do the right thing, failing if xs or ysresults in Nothing. for
> > instance, in the list monad, it will create the cross product of the
> > non Nothing members of the two lists. a parse monad may backtrack and
> > try another route, the IO monad will create a useful (and
> > deterministic/catchable) exception pointing to the exact file and line
> > number of the pattern match. The do notation is the only place in
> > haskell that allows us to hook into the pattern matching mechanism of
> > the language in a general way.
> > John
> I mention later that this is a "feature, not a bug" to some people, but I'm not one of them. The convenience of having this feature is IMO far outweighed by the cost of the runtime errors it can produce if you use the pattern matching in the wrong monad (e.g., IO, Reader, Writer...).
It seems like there must be deeper reasons than stated so far for wanting to remove the "failable" concept from the spec, because all the ones given so far seem more like pros than cons.
For example, those runtime errors would be type errors! And when adding additional constructors to a single-constructor type, it would not silently change the meaning in most places - it would cause type errors in places where the binding no longer makes sense and "change the meaning" in a predictable way (the way it does now) in places where it does make sense. The former sounds fantastic to me, and the latter sounds acceptable (but a warning for those who don't find it acceptable would be a good idea too).
There is of course still a risk that adding a constructor can cause silent misbehavior in code that uses those type of bindings in monads that _are_ instances of MonadZero, but personally the number of times I have been bitten by that or heard of anyone else actually being bitten by it (i.e., zero) is a lot smaller than the number of times I've decided a "failable" binding was just the right concise-and-clear way to implement a parser, filter, etc. The only problem I have with that style is the fact that it is not rejected in places where it doesn't make sense.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Haskell-Cafe