HORIZON HASKELLDocslts/ghc-9.14.xd82dee82026-10-12Search names, modules, packages, or :: a typeCtrl K

GHC 9.14.1 · lts/ghc-9.14.x · d82dee8 · 2026-10-12

Modulecapability-0.5.0.1Haskell2010

Capability.Error

Defines capabilities for actions that may fail or throw exceptions, and optionally may catch exceptions.

Monads based on IO can use the underlying IO exception mechanism to that end. The details of synchronous and asynchronous exception handling depend on the strategy used. See MonadThrow, SafeExceptions, MonadUnliftIO.

The associated tag can be used to select the exception type, or to select a layer in monad transformer stacks. Note, that it is illegal to have multiple tags refer to overlapping exception types in the same layer. Consider the following example

newtype M a = M (IO a)
  deriving (HasThrow "foo" IOException) via
    MonadUnliftIO IO
  deriving (HasThrow "bar" SomeException) via
    MonadUnliftIO IO

In this case the tags "foo" and "bar" refer to overlapping exception types in the same layer, because catch @"bar" may also catch an exception thrown under "foo".

  • 7 types
  • 4 classes
  • 8 values

Relational capabilities

6 declarations
classclass Monad m => HasThrow (tag :: k) e (m :: Type -> Type) | tag m -> e where
#

Capability to throw exceptions of type e under tag.

HasThrow/HasCatch capabilities at different tags should be independent. See HasCatch.

Methods

  • throw_ :: Proxy# tag -> e -> m a

    For technical reasons, this method needs an extra proxy argument. You only need it if you are defining new instances of HasReader. Otherwise, you will want to use throw. See throw for more documentation.

Instances12HasThrow, Reified, …
valuethrow :: HasThrow tag e m => e -> m a
#

Throw an exception in the specified exception capability.

classclass HasThrow tag e m => HasCatch (tag :: k) e (m :: Type -> Type) | tag m -> e where
#

Capability to catch exceptions of type e under tag.

HasThrow/HasCatch capabilities at different tags should be independent. In particular, the following program should throw SomeError and not return (). > example :: > (HasThrow Left SomeError m, HasCatch Right SomeError m) > => m () > example = > catch Left > (throw Right SomeError) > _ -> pure ()

See wrapError for a way to combine multiple exception types into one.

Methods

  • catch_ :: Proxy# tag -> m a -> (e -> m a) -> m a

    For technical reasons, this method needs an extra proxy argument. You only need it if you are defining new instances of HasReader. Otherwise, you will want to use catch. See catch for more documentation.

  • catchJust_ :: Proxy# tag -> (e -> Maybe b) -> m a -> (b -> m a) -> m a

    For technical reasons, this method needs an extra proxy argument. You only need it if you are defining new instances of HasReader. Otherwise, you will want to use catchJust. See catchJust for more documentation.

Instances11HasThrow, HasCatch, Reified, …
valuecatch :: HasCatch tag e m => m a -> (e -> m a) -> m a
#

Provide a handler for exceptions thrown in the given action in the given exception capability.

valuecatchJust :: HasCatch tag e m => (e -> Maybe b) -> m a -> (b -> m a) -> m a
#

Like catch, but only handle the exception if the provided function returns Just.

valuewrapError
  1. :: (forall x. Coercible (t m x) (m x), HasCatch innertag inner (t m), All cs m)
  2. => forall (m' :: Type -> Type). All (HasCatch innertag inner ': cs) m' => m' a
  3. -> m a
#

Wrap exceptions inner originating from the given action according to the accessor t. Retain arbitrary capabilities listed in cs.

Example:

wrapError
  @"ComponentError" @(Ctor "ComponentError" "AppError") @'[]
  component

component :: HasError "ComponentError" ComponentError m => m ()
data AppError = ComponentError ComponentError

This function is experimental and subject to change. See https://github.com/tweag/capability/issues/46.

Functional capabilities

3 declarations
typetype HasThrow' (tag :: k) = HasThrow tag (TypeOf k tag)
#

Type synonym using the TypeOf type family to specify HasThrow constraints without having to specify the type associated to a tag.

typetype HasCatch' (tag :: k) = HasCatch tag (TypeOf k tag)
#

Type synonym using the TypeOf type family to specify HasCatch constraints without having to specify the type associated to a tag.

familytype family TypeOf k (s :: k)
#

Type family associating a tag to the corresponding type. It is intended to simplify constraint declarations, by removing the need to redundantly specify the type associated to a tag.

It is poly-kinded, which allows users to define their own kind of tags. Standard haskell types can also be used as tags by specifying the Type kind when defining the type family instance.

Defining TypeOf instances for GHC.TypeLits.Symbols (typelevel string literals) is discouraged. Since symbols all belong to the same global namespace, such instances could conflict with others defined in external libraries. More generally, as for typeclasses, TypeOf instances should always be defined in the same module as the tag type to prevent issues due to orphan instances.

Example:

    import Capability.Reader

    data Foo
    data Bar
    type instance TypeOf Type Foo = Int
    type instance TypeOf Type Bar = String

    -- Same as: foo :: HasReader Foo Int M => …
    foo :: HasReader' Foo m => …
    foo = …

Strategies

5 declarations
newtypenewtype MonadError (m :: Type -> Type) a
#

Derive 'HasError from m's Control.Monad.Except.MonadError instance.

Constructors

Instances8HasCatch, HasThrow, Monad, Functor, Applicative, MonadIO, …
newtypenewtype MonadThrow e (m :: Type -> Type) a
#

Derive HasThrow from m's MonadThrow instance.

Constructors

Instances7HasThrow, Monad, Functor, Applicative, MonadIO, PrimMonad, …
newtypenewtype MonadCatch e (m :: Type -> Type) a
#

Derive 'HasCatch from m's 'Control.Monad.Catch.MonadCatch instance.

Constructors

Instances8HasCatch, HasThrow, Monad, Functor, Applicative, MonadIO, …
newtypenewtype SafeExceptions e (m :: Type -> Type) a
#

Derive HasError using the functionality from the safe-exceptions package.

Constructors

Instances8HasCatch, HasThrow, Monad, Functor, Applicative, MonadIO, …
newtypenewtype MonadUnliftIO e (m :: Type -> Type) a
#

Derive HasError using the functionality from the unliftio package.

Constructors

Instances8HasCatch, HasThrow, Monad, Functor, Applicative, MonadIO, …

Modifiers

Reflection

7 declarations
data familydata family Reified (tag :: k) (c :: Capability) (m :: Type -> Type)
#
Reified tag capability m

Defines the dictionary type for the methods of capability under tag in the monad m. Refer to interpret_ for an example use-case.

For example, the Capability.Sink.HasSink capability has the method Capability.Sink.yield :: a -> m (). The corresponding dictionary type is defined as follows.

Example1 expression
:{  data instance Reified tag (HasSink tag a) m =    ReifiedSink { _yield :: forall a. a -> m () }  :}

Superclass dictionaries are represented as nested records. For example, the Capability.State.HasState capability has the superclasses Capability.Source.HasSource and Capability.Sink.HasSink and the method Capability.State.state :: (s -> (a, s)) -> m a. The corresponding dictionary type is defined as follows.

Example1 expression
:{  data instance Reified tag (HasState tag s) m =    ReifiedState      { _stateSource :: Reified tag (HasSource tag s) m,        _stateSink :: Reified tag (HasSink tag s) m,        _state :: forall a. (s -> (a, s)) -> m a      }  :}
Instances7Reified, …

Re-exported

2 declarations
classclass (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

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

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

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 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

Methods

Instances46Exception, …