Newbie Question about Error Handling

Hello! I'm confused by the error handling in Haskell. I've written a program that uses a combined monad of type: type MyMonad a = ErrorT MyErrorType (StateT MyStateType IO) a (MyErrorType is an instance of Error) Therefore, to handle IO Errors inside of MyMonad I need to write: foo :: MyMonad a foo = do ... inp <- liftIO (getChar `catchError` (\e -> if isEOFError e then return '\0' else return '?') ) case inp of '\?' -> throwError ... .... `catchError` myErrorTypeHandler This of course is cumbersome and ugly and I'm sure there is a way to do better. Helpful advice is welcome! _________________________________________________________________ FREE pop-up blocking with the new MSN Toolbar - get it now! http://toolbar.msn.click-url.com/go/onm00200415ave/direct/01/

On Sun, Jul 24, 2005 at 08:00:58PM +0000, Gerd M wrote:
Hello! I'm confused by the error handling in Haskell. I've written a program that uses a combined monad of type: type MyMonad a = ErrorT MyErrorType (StateT MyStateType IO) a (MyErrorType is an instance of Error)
Therefore, to handle IO Errors inside of MyMonad I need to write: foo :: MyMonad a foo = do ... inp <- liftIO (getChar `catchError` (\e -> if isEOFError e then return '\0' else return '?') ) case inp of '\?' -> throwError ...
So you're trying to get the IO error back out into an ErrorT error. I made my own exploration of this issue[1] recently and came up with liftError :: (MonadError e m, MonadTrans t, MonadError e (t m)) => m a -> t m a liftError m = join (lift (liftM return m `catch` (return . throw))) However, it doesn't help you directly, because it assumes that the error types are the same in the inner and outer monads. Also, the definition is rather compact. So let's start by just rewriting your code foo :: MyMonad a foo = do minp <- liftIO (do c <- getChar return (return c) `catchError` (\e -> if isEOFError e then return (return '\0') else return (throwError ...)) :: IO (MyMonad Char)) inp <- minp ... We're being clever and returning from IO not a Char, but a MyMonad Char (mimp). Then, we run that, which either produces the answer we wanted, or throws an error in MyMonad. However, it's still rather cumbersome, so here's a function similar to liftError that works for your monad. -- I'll assume you have such a function fromIOError :: IOError -> MyErrorType -- The name is intended to convey that IO errors are caught and -- reintroduced into MyMonad. Better suggestions welcome. liftIOTrap :: IO a -> MyMonad a liftIOTrap io = do mx <- liftIO (do x <- io return (return x) `catchError` (\e -> return (throwError (fromIOError e)))) mx foo :: MyMonad a foo = do inp <- liftIOTrap (getChar `catchError` (\e -> if isEOFError e then return '\0' else throwError e)) ... Andrew [1] http://haskell.org/pipermail/haskell-cafe/2005-June/010361.html

We're being clever and returning from IO not a Char, but a MyMonad Char (mimp). Then, we run that, which either produces the answer we wanted, or throws an error in MyMonad. Thanks. That did the trick! :-) Regards
However, it's still rather cumbersome, so here's a function similar to liftError that works for your monad.
-- I'll assume you have such a function fromIOError :: IOError -> MyErrorType
-- The name is intended to convey that IO errors are caught and -- reintroduced into MyMonad. Better suggestions welcome. liftIOTrap :: IO a -> MyMonad a liftIOTrap io = do mx <- liftIO (do x <- io return (return x) `catchError` (\e -> return (throwError (fromIOError e)))) mx
foo :: MyMonad a foo = do inp <- liftIOTrap (getChar `catchError` (\e -> if isEOFError e then return '\0' else throwError e)) ...
Andrew
[1] http://haskell.org/pipermail/haskell-cafe/2005-June/010361.html
_________________________________________________________________ Express yourself instantly with MSN Messenger! Download today it's FREE! http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/
participants (2)
-
Andrew Pimlott
-
Gerd M