[Haskell-beginners] How to make a kinder, gentler 'fail'?

Elvio Toccalino elviotoccalino at gmail.com
Thu May 26 22:05:23 CEST 2011


Just checked the package doc, and apparently there's no instance of
Failure for the (Either String) monad. For that case 'failure = Left',
but looking at the docs I see the following (cryptic, to me) comment:

-- not a monad or applicative instance Failure e (Either e) where
failure = Left

(I suppose It's there because that 'e' type variable is not bound to
String, as we'd like)

BUT! I also see that (Either e) is an instance of the (similar?) Try
type class:

class Try f where
  type Error f
  -- Turn a concrete failure into an abstract failure
  try :: Failure (Error f) f' => f a -> f' a

instance Try (Either e) where
  type Error (Either e) = e
  try (Left  e)         = failure e
  try (Right x)         = return x

Through this Try instance, you should be able to 'try action', where
action has 'Either String some' type, and the failures you throw in such
action would be translated to Left's.

On Thu, 2011-05-26 at 12:19 -0700, Sean Perry wrote:
> Yes, this sounds like what I want but I can not get it to work how I want (-:
> 
> Monad Reader 15 is where this is discussed. Apparently MonadFailure has been
> replaced with Failure.
> From M.R 15 here is the example:
> safeHeadFailure :: Failure String m => [a] -> m a
> safeHeadFailure [] = failure "empty list"
> safeHeadFailure (x:xs) = return x
> 
> safeHead' :: [a] -> Maybe a
> safeHead' = safeHeadFailure
> 
> and sure enough, safeHead' works in Maybe. But if I change it to
> 
> safeHead' :: [a] -> Either String a
> 
> which is more like what will happen in real code I get:
> 
>     No instance for (Failure String (Either String))
>       arising from a use of `safeHeadFailure'
>     Possible fix:
>       add an instance declaration for (Failure String (Either String))
>     In the expression: safeHeadFailure
>     In an equation for `safeHead'': safeHead' = safeHeadFailure
> 
> Yes, I installed control-monad-failure-mtl and yes I have a 'import
> Control.Monad.Error' directive in the module.
> 
> This is straight from the article:
> 
> safeHeadPair' :: Failure String m => [a] -> [b] -> m (a, b)
> safeHeadPair' [] [] = failure "both lists empty"
> safeHeadPair' [] _ = failure "first list empty"
> safeHeadPair' _ [] = failure "second list empty"
> safeHeadPair' (x:xs) (y:ys) = return (x, y)
> 
> safeHead2 :: [a] -> [b] -> Either String (a, b)
> safeHead2 = safeHeadPair'
> 
> I get the same failure here.
> 
> What am I missing?
> 
> On Thu May 26 11:24 , Elvio Toccalino  sent:
> 
> >Well, there's the 'failure' package. Another package builds on top of
> >it, the control-monad-failure (easier to use, maybe).
> >I read in the monad reader (don't remember the issue number) about it,
> >and have used it ever since. The idea is to let the instanced monad
> >decide what a failure means.
> >Check it out, and comment back.
> >
> >Cheers.
> >
> >On Thu, 2011-05-26 at 11:15 -0700, Sean Perry wrote:
> >> This is probably a FAQ of sorts, but I found composing the proper search terms
> >> complicated.
> >> 
> >> When I write simple parsers and the like I tend to prefer returning useful error
> >> strings instead of simply Nothing from Maybe.
> >> 
> >> For example this is a common utility function of mine. Yes, I know with the
> >> addition of a Read n qualification I can make this more
> >> generic but it does not help with the current discussion.
> >> 
> >> getNum :: String -> Either String Int
> >> getNum n = case reads n of [(x, "")] -> Right x
> >>                            [(x, cs)] -> Left $ "incomplete parse: " ++ cs
> >>                            cs        -> Left $ "invalid number: " ++ cs
> >> 
> >> But I would rather write the following so I am not bound to Either. This would
> >> even work with Maybe since Nothing just drops the string from fail.
> >> 
> >> getNum :: Monad m => String -> m Int
> >> getNum n = case reads n of [(x, "")] -> return x
> >>                            [(x, cs)] -> fail $ "incomplete parse: " ++ cs
> >>                            cs        -> fail $ "invalid number: " ++ cs
> >> 
> >> Yeah, I know, no one likes the fact that fail raises an exception. What I would
> >> like to do in my code is define something like
> >> 
> >> class (Monad a) => MonadGentle a where
> >>     myreturn = return
> >>     myfail s = fails s
> >> 
> >> But I can not get an instance of this to compile because it insists myreturn and
> >> myfail are not visible.
> >> 
> >> Since this comes up a lot in the tutorials and books, I am curious why there is
> >> not something like MonadGentle in Hackage or the libs. I use mzero occasionally,
> >> but as I said I usually prefer some information with my errors since it makes for
> >> more human usable results.
> >> 
> >> Thanks.
> >> 
> >> 
> >> _______________________________________________
> >> Beginners mailing list
> >> Beginners at haskell.org
> >> http://www.haskell.org/mailman/listinfo/beginners
> >
> >
> 
> 
> 
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners





More information about the Beginners mailing list