
On Mon, Dec 16, 2013 at 2:54 PM, Tom Ellis < tom-lists-haskell-cafe-2013@jaguarpaw.co.uk> wrote:
On Mon, Dec 16, 2013 at 11:26:39PM +0100, David Luposchainsky wrote:
I feel like there are a couple of elephants in the room that are sort of important but nobody really addresses them directly. One of them was what became the AMP, and `fail` is another one.
Is it written up somewhere why pattern match failure in 'do' is a 'fail' but pattern match failure elsewhere is just pattern match failure?
Malcolm Wallace mentioned that it convenient when writing parsers, and his example is indeed neat, but is has someone done a more substantial investigation the benefits of this special case?
AFAIK, it was done this way for list comprehensions. Currently, you can write e.g.
rights = [x | Right x <- listOfEithers]
and it works properly. The list comprehension is desugared to
do { Right x <- listOfEithers; return x }
which becomes
do { listOfEithers >>= \l -> case l of { Right x -> return x; _ -> fail "location" }}
since the Monad instance for lists defines fail = const [], everything works out. The nearly-equivalent code,
listOfEithers >>= \(Right x) -> return x
indeed results in a PatternMatchFail exception. The difference is that in the former case, the fail method is called in lieu of the remainder of the do-expression, whereas the lambda pattern match failure calls throw. Throwing an exception wouldn't work for this because they can't be caught outside IO. (I think this applies to generalized monad comprehensions as well, although I've never tried that)