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

_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to