
Thanks a lot! It took me a while to understand what you meant but
eventually I got it.
This is the final version and it looks much better:
f :: MyMonad String
f = do
liftIO $ putStrLn "Please enter a file name: "
name ← liftIO getLine
hFile ← ErrorT $ (openFile name ReadMode ↠ return.Right)
`catch` λ_ → return.Left $ KnownErr "open failed"
content ← liftIO $ hGetContents hFile
return content
Somehow I understand but I don't have the feeling yet why I apply
ErrorT to the whole catched expression instead of liftIO. Do you have
a nice explanation for it?
Ovidiu
On Sat, Sep 24, 2011 at 10:21 PM, Daniel Fischer
On Saturday 24 September 2011, 19:52:24, Ovidiu Deac wrote:
Given this function
f :: MyMonad String f = do liftIO $ putStrLn "Please enter a file name: " name ← liftIO getLine hFile ← liftIO $ openFile name ReadMode content ← liftIO $ hGetContents hFile return $ content
I would like to catch the error thrown by openFile and translate it to my own exception type.
So first I tried this: hFile ← (liftIO $ openFile name ReadMode) `catch` λ_ → throwError (KnownErr "open failed")
catch has type (IO a -> (e -> IO a) -> IO a) [where e = IOError if you're using Prelude.catch, and e can be any instance of Exception if you're using Control.Exception.catch (recommended)].
But (liftIO ioAction) has type (MyMonad a), so that can't be used as an argument to catch. Nor can (\_ -> throwError (KnownErr "...")).
..but it fails because the error handler is returning a different type then the "try block". Right?
No, it fails because both have the wrong type for catch. It would typecheck with catchError instead of catch, but that wouldn't catch the error :(
Then I tried this: f = do liftIO $ putStrLn "Please enter a file name: " name ← liftIO getLine hFile ← (liftIO $ openFile name ReadMode ↠ return.Right) `catch` λ_ → return (Left $ KnownErr "open failed")
Close. If you replace liftIO with ErrorT in that line and move the first open parenthesis past the $, then it works and does what you want. Without changing the following two lines (or, better, do change them; do x <- act return x
is the same as just
act ). liftIO adds a layer of Either, ErrorT doesn't.
hFile <- ErrorT $ liftM Right (openFile name ReadMode) `catch` (\_ -> return $ Left (KnownErr "open failed")) liftIO $ hGetContents hFile