
On Fri, Dec 22, 2006 at 08:37:05PM -0500, Steve Downey wrote:
On 12/22/06, Stefan O'Rear
wrote: All monads provide a "fail" operation, and any function that uses fail will be able to work with any monad's error handling mechanism.
* Maybe - fail msg is Nothing (ignores the message) * Either str - fail msg is Left msg (stores the message) * IO - fail msg is ioError (userError msg) (throws message as exception)
OK, but is msg always a string?
You've hit the nail on the head. The fail method is a kludge that works if the error is just a string (in English, of course), but often it isn't.
For instance, Data.Map.minView is Monad m => Set a -> m (Set a, a); so..
minView :: Set a -> Maybe (Set a, a) -- gives Nothing on empty set minView :: Set a -> [(Set a, a)] -- gives [] on empty set minView :: Set a -> IO (Set a, a) -- throws an ioError on empty set ...
(note that the behavior of lookup et al, which are specific to Maybe, is considered outdated style)
I feel a bit queasy about this. With the old Maybe type of minView, it really was a view: the empty case was an element of the data type, not an error. You could pattern match on it, and the empty case would often be perfectly normal. Of course you can still do that, because the old type is a special case that's still available, but the change of perspective gives the wrong impression, I think. It feels wrong to use failure as a normal execution path.