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.