how to catch the error thrown by openFile?

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") ..but it fails because the error handler is returning a different type then the "try block". Right? 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") case hFile of Right handle → do content ← liftIO $ hGetContents hFile return $ content Left error → throwError error ...which also fails with Couldn't match expected type `ErrorT MyType IO t0' with actual type `IO a0' In a stmt of a 'do' expression: hFile <- (do { handle <- liftIO $ openFile name ReadMode; return (Right handle) }) `catch` \ _ -> return (Left $ KnownErr "open failed") Any help is appreciated. Thanks! Full code here: import Control.Monad.Error import System.IO data MyType = UnknownErr | KnownErr String deriving (Show) instance Error MyType where noMsg = UnknownErr strMsg str = KnownErr str type MyMonad = ErrorT MyType IO main = do r ← runErrorT f reportResult r 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 reportResult (Right c) = putStrLn ("The content is " ⊕ c) reportResult (Left e) = putStrLn ("Error: " ⊕ (show e))

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
participants (2)
-
Daniel Fischer
-
Ovidiu Deac