code / art / projects

When Is It Okay to “Fail”?

That’s the question.

In designing a couple libraries the question of the proper use of the Monad class’s fail method has come up more than once.

On the one hand, many people consider fail to be a wart on the face of an otherwise pure implementation of an elegant construction borrowed from category theory. It’s as if someone defined scissors as

“two metal blades with handles, attached by a pivot… plus a bandaid in case you cut yourself”.

But on the other hand many instances of Monad have a logical and intuitive way of encapsulating failure, whether it be Nothing in Maybe, or the empty list in []. And for monad’s that have no reasonable way of encapsulating failure, a default method (raising an exception) can be used.

Something I learned just recently is that the haskell report specifies that, as part of desugaring “do notation”, fail will be raised on a monadic pattern match failure. Check it out:

test :: Maybe [Int]
test = do
    (x:xs) <- Just [] -- pattern match fail
    return xs -- returns Nothing!

The haskell library writer also has the option of using MonadPlus which provides an explicit mzero method, instead of using the dirty, dirty fail method.

But if we care only about the error-catching properties of a monad and not the monoidal, mplus combining property isn’t that also ugly?

I’ve been trying to research the question of whether there are any Monads with a logical fail method that cannot be members of MonadPlus because they have no reasonable mplus definition.

I might ask on stack overflow, and will update the post if I do and the feedback is interesting.

Thanks as always, and let me know your thoughts on this whole question.