Leo Zhang
Leo Zhang

Reputation: 3230

How to catch Exception from IO and print its error.

I'd like to catch exceptions from the IO and inspect what kind of exception was raised with typeOf and then use the specific exception to pattern match in order to handle the exception specifically. But the following code doesn't work as I expected.

import Control.Exception (SomeException, handle)
import Data.Typeable (typeOf)
import System.Environment (getEnv)

main :: IO ()
main = handle missingEnv exe
  where
    exe = do
      env <- getEnv "MISSING_ENV"
      print env
      file <- readFile "/file-does-not-exist"
      print file

missingEnv :: SomeException -> IO ()
missingEnv e = do
  print e
  print $ typeOf e
  return ()

The above code will print the following error, but it only shows "SomeException", which doesn't have the specific name for the type of the Exception.

MISSING_ENV: getEnv: does not exist (no environment variable)
SomeException

You might suggest me to use lookupEnv, but that's not my point, because I'd like to learn how to catch an exception, rather than how to avoid an exception.

Is it possible to inspect the specific "type" of a raised exception from IO?

Also is it possible to inspect the specific "type" of a raised exception from MonadError?

Upvotes: 1

Views: 393

Answers (2)

Daniel Wagner
Daniel Wagner

Reputation: 152837

You've subverted the entire exception-type-matching mechanism by using SomeException. If you want to handle a specific kind of exception, just do that, don't convert into and out of SomeException along the way. For example:

import Control.Exception (IOException, handle, throwIO)
import System.Environment (getEnv)
import System.IO.Error (isDoesNotExistError)

main :: IO ()
main = handle missingEnv exe
  where
    exe = do
      env <- getEnv "MISSING_ENV"
      print env
      file <- readFile "/file-does-not-exist"
      print file

missingEnv :: IOException -> IO ()
missingEnv e | isDoesNotExistError = print e
             | otherwise = throwIO e

Upvotes: 2

bergey
bergey

Reputation: 3071

Yes, you can inspect the type of the exception:

logSomeException :: SomeException -> IO ()
logSomeException (SomeException e) = print (typeOf e)

Upvotes: 2

Related Questions