[Haskell-beginners] how to catch the error thrown by openFile?

Daniel Fischer daniel.is.fischer at googlemail.com
Sat Sep 24 21:21:59 CEST 2011


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



More information about the Beginners mailing list