Control.Monad.Catch

exceptions-0.8.0.2: Extensible optionally-pure exceptions

Copyright | (C) Edward Kmett 2013-2015, (c) Google Inc. 2012
License | BSD-style (see the file LICENSE)
Maintainer | Edward Kmett <ekmett@gmail.com>
Stability | experimental
Portability | non-portable
Safe Haskell | Trustworthy
Language | Haskell98

Control.Monad.Catch

Contents

- Typeclass
- Utilities
- Re-exports from Control.Exception

Description

This module supports monads that can throw extensible exceptions. The exceptions are the very same from Control.Exception, and the operations offered very similar, but here they are not limited to `IO`.

This code is in the style of both transformers and mtl, and is compatible with them, though doesn't mimic the module structure or offer the complete range of features in those packages.

This is very similar to `ErrorT` and `MonadError`, but based on features of Control.Exception. In particular, it handles the complex case of asynchronous exceptions by including `mask` in the typeclass. Note that the extensible extensions feature relies on the RankNTypes language extension.

Synopsis

- class Monad m => MonadThrow m where
  - throwM :: Exception e => e -> m a
- class MonadThrow m => MonadCatch m where
  - catch :: Exception e => m a -> (e -> m a) -> m a
- class MonadCatch m => MonadMask m where
  - mask :: ((forall a. m a -> m a) -> m b) -> m b
  - uninterruptibleMask :: ((forall a. m a -> m a) -> m b) -> m b
- mask_ :: MonadMask m => m a -> m a
- uninterruptibleMask_ :: MonadMask m => m a -> m a
- catchAll :: MonadCatch m => m a -> (SomeException -> m a) -> m a
- catchIOError :: MonadCatch m => m a -> (IOError -> m a) -> m a
- catchJust :: (MonadCatch m, Exception e) => (e -> Maybe b) -> m a -> (b -> m a) -> m a
- catchIf :: (MonadCatch m, Exception e) => (e -> Bool) -> m a -> (e -> m a) -> m a
- data Handler m a = forall e . Exception e => Handler (e -> m a)
- catches :: (Foldable f, MonadCatch m) => m a -> f (Handler m a) -> m a
- handle :: (MonadCatch m, Exception e) => (e -> m a) -> m a -> m a
- handleAll :: MonadCatch m => (SomeException -> m a) -> m a -> m a
- handleIOError :: MonadCatch m => (IOError -> m a) -> m a -> m a
- handleJust :: (MonadCatch m, Exception e) => (e -> Maybe b) -> (b -> m a) -> m a -> m a
- handleIf :: (MonadCatch m, Exception e) => (e -> Bool) -> (e -> m a) -> m a -> m a
- try :: (MonadCatch m, Exception e) => m a -> m (Either e a)
- tryJust :: (MonadCatch m, Exception e) => (e -> Maybe b) -> m a -> m (Either b a)
- onException :: MonadCatch m => m a -> m b -> m a
- bracket :: MonadMask m => m a -> (a -> m b) -> (a -> m c) -> m c
- bracket_ :: MonadMask m => m a -> m b -> m c -> m c
- finally :: MonadMask m => m a -> m b -> m a
- bracketOnError :: MonadMask m => m a -> (a -> m b) -> (a -> m c) -> m c
- class (Typeable * e, Show e) => Exception e where
  - toException :: e -> SomeException
  - fromException :: SomeException -> Maybe e
  - displayException :: e -> String
- data SomeException :: * where
  - SomeException :: Exception e => e -> SomeException

# Typeclass

The mtl style typeclass

class Monad m => MonadThrow m where

A class for monads in which exceptions may be thrown.

Instances should obey the following law:

    throwM e >> x = throwM e

In other words, throwing an exception short-circuits the rest of the monadic computation.

Methods

throwM :: Exception e => e -> m a

Throw an exception. Note that this throws when this action is run in the monad `m`, not when it is applied. It is a generalization of Control.Exception's `throwIO`.

Should satisfy the law:

    throwM e >> f = throwM e

Instances

MonadThrow [] |
MonadThrow IO |
MonadThrow STM |
MonadThrow Maybe |
(~) * e SomeException => MonadThrow (Either e) |
MonadThrow m => MonadThrow (ListT m) |
MonadThrow m => MonadThrow (MaybeT m) | Throws exceptions into the base monad.
MonadThrow m => MonadThrow (IdentityT m) |
Monad m => MonadThrow (CatchT m) |
MonadThrow m => MonadThrow (ContT r m) |
MonadThrow m => MonadThrow (ReaderT r m) |
MonadThrow m => MonadThrow (StateT s m) |
MonadThrow m => MonadThrow (StateT s m) |
MonadThrow m => MonadThrow (ExceptT e m) | Throws exceptions into the base monad.
(Error e, MonadThrow m) => MonadThrow (ErrorT e m) | Throws exceptions into the base monad.
(MonadThrow m, Monoid w) => MonadThrow (WriterT w m) |
(MonadThrow m, Monoid w) => MonadThrow (WriterT w m) |
(MonadThrow m, Monoid w) => MonadThrow (RWST r w s m) |
(MonadThrow m, Monoid w) => MonadThrow (RWST r w s m) |

class MonadThrow m => MonadCatch m where

A class for monads which allow exceptions to be caught, in particular exceptions which were thrown by `throwM`.

Instances should obey the following law:

    catch (throwM e) f = f e

Note that the ability to catch an exception does not guarantee that we can deal with all possible exit points from a computation. Some monads, such as continuation-based stacks, allow for more than just a success/failure strategy, and therefore `catch` cannot be used by those monads to properly implement a function such as `finally`. For more information, see `MonadMask`.

Methods

catch :: Exception e => m a -> (e -> m a) -> m a

Provide a handler for exceptions thrown during execution of the first action. Note that type of the type of the argument to the handler will constrain which exceptions are caught. See Control.Exception's `catch`.

Instances

MonadCatch IO |
MonadCatch STM |
MonadCatch m => MonadCatch (ListT m) |
MonadCatch m => MonadCatch (MaybeT m) | Catches exceptions from the base monad.
MonadCatch m => MonadCatch (IdentityT m) |
Monad m => MonadCatch (CatchT m) |
MonadCatch m => MonadCatch (ReaderT r m) |
MonadCatch m => MonadCatch (StateT s m) |
MonadCatch m => MonadCatch (StateT s m) |
MonadCatch m => MonadCatch (ExceptT e m) | Catches exceptions from the base monad.
(Error e, MonadCatch m) => MonadCatch (ErrorT e m) | Catches exceptions from the base monad.
(MonadCatch m, Monoid w) => MonadCatch (WriterT w m) |
(MonadCatch m, Monoid w) => MonadCatch (WriterT w m) |
(MonadCatch m, Monoid w) => MonadCatch (RWST r w s m) |
(MonadCatch m, Monoid w) => MonadCatch (RWST r w s m) |

class MonadCatch m => MonadMask m where

A class for monads which provide for the ability to account for all possible exit points from a computation, and to mask asynchronous exceptions. Continuation-based monads, and stacks such as `ErrorT e IO` which provide for multiple failure modes, are invalid instances of this class.

Note that this package does provide a `MonadMask` instance for `CatchT`. This instance is only valid if the base monad provides no ability to provide multiple exit. For example, `IO` or `Either` would be invalid base monads, but `Reader` or `State` would be acceptable.

Instances should ensure that, in the following code:

    f `finally` g

The action `g` is called regardless of what occurs within `f`, including async exceptions.

Methods

mask :: ((forall a. m a -> m a) -> m b) -> m b

Runs an action with asynchronous exceptions disabled. The action is provided a method for restoring the async. environment to what it was at the `mask` call. See Control.Exception's `mask`.

uninterruptibleMask :: ((forall a. m a -> m a) -> m b) -> m b

Like `mask`, but the masked computation is not interruptible (see Control.Exception's `uninterruptibleMask`. WARNING: Only use if you need to mask exceptions around an interruptible operation AND you can guarantee the interruptible operation will only block for a short period of time. Otherwise you render the program/thread unresponsive and/or unkillable.

Instances

MonadMask IO |
MonadMask m => MonadMask (IdentityT m) |
Monad m => MonadMask (CatchT m) | Note: This instance is only valid if the underlying monad has a single exit point!
MonadMask m => MonadMask (ReaderT r m) |
MonadMask m => MonadMask (StateT s m) |
MonadMask m => MonadMask (StateT s m) |
(MonadMask m, Monoid w) => MonadMask (WriterT w m) |
(MonadMask m, Monoid w) => MonadMask (WriterT w m) |
(MonadMask m, Monoid w) => MonadMask (RWST r w s m) |
(MonadMask m, Monoid w) => MonadMask (RWST r w s m) |

# Utilities

These functions follow those from Control.Exception, except that they are based on methods from the `MonadCatch` typeclass. See Control.Exception for API usage.

mask_ :: MonadMask m => m a -> m a

Like `mask`, but does not pass a `restore` action to the argument.

uninterruptibleMask_ :: MonadMask m => m a -> m a

Like `uninterruptibleMask`, but does not pass a `restore` action to the argument.

catchAll :: MonadCatch m => m a -> (SomeException -> m a) -> m a

Catches all exceptions, and somewhat defeats the purpose of the extensible exception system. Use sparingly.

catchIOError :: MonadCatch m => m a -> (IOError -> m a) -> m a

Catch all `IOError` (eqv. `IOException`) exceptions. Still somewhat too general, but better than using `catchAll`. See `catchIf` for an easy way of catching specific `IOError`s based on the predicates in System.IO.Error.

catchJust :: (MonadCatch m, Exception e) => (e -> Maybe b) -> m a -> (b -> m a) -> m a

A more generalized way of determining which exceptions to catch at run time.

catchIf :: (MonadCatch m, Exception e) => (e -> Bool) -> m a -> (e -> m a) -> m a

Catch exceptions only if they pass some predicate. Often useful with the predicates for testing `IOError` values in System.IO.Error.

data Handler m a

Generalized version of `Handler`

Constructors

forall e . Exception e => Handler (e -> m a) |

Instances

Monad m => Functor (Handler m) |

catches :: (Foldable f, MonadCatch m) => m a -> f (Handler m a) -> m a

Catches different sorts of exceptions. See Control.Exception's `catches`

handle :: (MonadCatch m, Exception e) => (e -> m a) -> m a -> m a

Flipped `catch`. See Control.Exception's `handle`.

handleAll :: MonadCatch m => (SomeException -> m a) -> m a -> m a

Flipped `catchAll`

handleIOError :: MonadCatch m => (IOError -> m a) -> m a -> m a

Flipped `catchIOError`

handleJust :: (MonadCatch m, Exception e) => (e -> Maybe b) -> (b -> m a) -> m a -> m a

Flipped `catchJust`. See Control.Exception's `handleJust`.

handleIf :: (MonadCatch m, Exception e) => (e -> Bool) -> (e -> m a) -> m a -> m a

Flipped `catchIf`

try :: (MonadCatch m, Exception e) => m a -> m (Either e a)

Similar to `catch`, but returns an `Either` result. See Control.Exception's `try`.

tryJust :: (MonadCatch m, Exception e) => (e -> Maybe b) -> m a -> m (Either b a)

A variant of `try` that takes an exception predicate to select which exceptions are caught. See Control.Exception's `tryJust`

onException :: MonadCatch m => m a -> m b -> m a

Run an action only if an exception is thrown in the main action. The exception is not caught, simply rethrown.

bracket :: MonadMask m => m a -> (a -> m b) -> (a -> m c) -> m c

Generalized abstracted pattern of safe resource acquisition and release in the face of exceptions. The first action "acquires" some value, which is "released" by the second action at the end. The third action "uses" the value and its result is the result of the `bracket`.

If an exception occurs during the use, the release still happens before the exception is rethrown.

bracket_ :: MonadMask m => m a -> m b -> m c -> m c

Version of `bracket` without any value being passed to the second and third actions.

finally :: MonadMask m => m a -> m b -> m a

Perform an action with a finalizer action that is run, even if an exception occurs.

bracketOnError :: MonadMask m => m a -> (a -> m b) -> (a -> m c) -> m c

Like `bracket`, but only performs the final action if there was an exception raised by the in-between computation.

# Re-exports from Control.Exception

class (Typeable * e, Show e) => Exception e where

Any type that you wish to throw or catch as an exception must be an instance of the `Exception` class. The simplest case is a new exception type directly below the root:

    data MyException = ThisException | ThatException
        deriving (Show, Typeable)

    instance Exception MyException

The default method definitions in the `Exception` class do what we need in this case. You can now throw and catch `ThisException` and `ThatException` as exceptions:

    *Main> throw ThisException `catch` \e -> putStrLn ("Caught " ++ show (e :: MyException))
    Caught ThisException

In more complicated examples, you may wish to define a whole hierarchy of exceptions:

    ---------------------------------------------------------------------
    -- Make the root exception type for all the exceptions in a compiler

    data SomeCompilerException = forall e . Exception e => SomeCompilerException e
        deriving Typeable

    instance Show SomeCompilerException where
        show (SomeCompilerException e) = show e

    instance Exception SomeCompilerException

    compilerExceptionToException :: Exception e => e -> SomeException
    compilerExceptionToException = toException . SomeCompilerException

    compilerExceptionFromException :: Exception e => SomeException -> Maybe e
    compilerExceptionFromException x = do
        SomeCompilerException a <- fromException x
        cast a

    ---------------------------------------------------------------------
    -- Make a subhierarchy for exceptions in the frontend of the compiler

    data SomeFrontendException = forall e . Exception e => SomeFrontendException e
        deriving Typeable

    instance Show SomeFrontendException where
        show (SomeFrontendException e) = show e

    instance Exception SomeFrontendException where
        toException = compilerExceptionToException
        fromException = compilerExceptionFromException

    frontendExceptionToException :: Exception e => e -> SomeException
    frontendExceptionToException = toException . SomeFrontendException

    frontendExceptionFromException :: Exception e => SomeException -> Maybe e
    frontendExceptionFromException x = do
        SomeFrontendException a <- fromException x
        cast a

    ---------------------------------------------------------------------
    -- Make an exception type for a particular frontend compiler exception

    data MismatchedParentheses = MismatchedParentheses
        deriving (Typeable, Show)

    instance Exception MismatchedParentheses where
        toException   = frontendExceptionToException
        fromException = frontendExceptionFromException

We can now catch a `MismatchedParentheses` exception as `MismatchedParentheses`, `SomeFrontendException` or `SomeCompilerException`, but not other types, e.g. `IOException`:

    *Main> throw MismatchedParentheses catch e -> putStrLn ("Caught " ++ show (e :: MismatchedParentheses))
    Caught MismatchedParentheses
    *Main> throw MismatchedParentheses catch e -> putStrLn ("Caught " ++ show (e :: SomeFrontendException))
    Caught MismatchedParentheses
    *Main> throw MismatchedParentheses catch e -> putStrLn ("Caught " ++ show (e :: SomeCompilerException))
    Caught MismatchedParentheses
    *Main> throw MismatchedParentheses catch e -> putStrLn ("Caught " ++ show (e :: IOException))
    *** Exception: MismatchedParentheses

Minimal complete definition

Nothing

Methods

toException :: e -> SomeException

fromException :: SomeException -> Maybe e

displayException :: e -> String

Render this exception value in a human-friendly manner.

Default implementation: ``show``.

Since: 4.8.0.0

Instances

Exception PatternMatchFail |
Exception RecSelError |
Exception RecConError |
Exception RecUpdError |
Exception NoMethodError |
Exception NonTermination |
Exception NestedAtomically |
Exception BlockedIndefinitelyOnMVar |
Exception BlockedIndefinitelyOnSTM |
Exception Deadlock |
Exception AllocationLimitExceeded |
Exception AssertionFailed |
Exception SomeAsyncException |
Exception AsyncException |
Exception ArrayException |
Exception ExitCode |
Exception IOException |
Exception ErrorCall |
Exception ArithException |
Exception SomeException |

data SomeException :: * where

The `SomeException` type is the root of the exception type hierarchy. When an exception of type `e` is thrown, behind the scenes it is encapsulated in a `SomeException`.

Constructors

SomeException :: Exception e => e -> SomeException |

Instances

Show SomeException |
Exception SomeException |