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

Ovidiu Deac ovidiudeac at gmail.com
Sun Sep 25 00:27:54 CEST 2011


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
<daniel.is.fischer at googlemail.com> wrote:
> 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