tagged-exception-core-2.2.0.0: Reflect exceptions using phantom types.

Copyright(c) 2009-2016, Peter Trško
LicenseBSD3
Stabilityprovisional
PortabilityNoImplicitPrelude, depends on non-portable modules
Safe HaskellSafe
LanguageHaskell2010

Control.Monad.TaggedException.Core

Contents

Description

Core functionality.

Synopsis

Throw, Catch and Map Exceptions

throw :: (Exception e, MonadThrow m) => e -> Throws e m a Source

Throw an exception. To raise an "inner" exception following can be used:

liftT . throw
    :: (MonadCatch m, Exception e, Exception e')
    => e
    -> Throws e' (Throws e m) a

catch :: (Exception e, MonadCatch m) => Throws e m a -> (e -> m a) -> m a Source

Catch exception.

To catch inner exception following construct can be used:

catch . flipT
    :: (Exception e, Exception e', MonadCatch m)
    => Throws e' (Throws e m) a
    -> (e -> Throws e' m a)
    -> Throws e' m a

catch' :: (Exception e, MonadCatch m) => m a -> (e -> m a) -> m a Source

Catch any exception.

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

Flipped version of catch. Usage example:

foo = handle exceptionHandler $ do
    ...
  where exceptionHandler = ...

Handle "inner" exception:

insideT . handle
    :: (MonadCatch m, Exception e, Exception e')
    => (e' -> m a)
    -> Throws e (Throws e' m) a
    -> Throws e m a

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

Flipped version of catch'

mapException :: (Exception e, Exception e', MonadCatch m) => (e -> e') -> Throws e m a -> Throws e' m a Source

Map one exception to another.

Mapping "inner" exception has generally two forms:

1. Modifying raised exception, but not changing its type:

liftT1 . mapException
    :: (Exception e, Exception e', MonadCatch m)
    => (e -> e)
    -> Throws e' (Throws e m) a
    -> Throws e' (Throws e m) a

2. Modifying raised exception, including its type:

insideT . mapException
    :: (Exception e, Exception e1, Exception e2, MonadCatch m)
    => (e1 -> e2)
    -> Throws e (Throws e1 m) a
    -> Throws e (Throws e2 m) a

Unhiding exception by mapping it in to a different type of exception:

\f -> mapException f . liftT
    :: (Exception e, Exception e', MonadCatch m)
    => (e -> e')
    -> m a
    -> Throws e' m a

Specialized Exception Catching

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

Similar to catch, but returns Either exception or result.

Inner try:

try . flipT
    :: (Exception e, Exception e', MonadCatch m)
    => Throws e' (Throws e m) a
    -> Throws e' m (Either e a)

onException Source

Arguments

:: (Exception e, MonadCatch m) 
=> Throws e m a

Computation that may raise exception

-> m b

The computation to run if an exception e is raised

-> Throws e m a 

Run computation if exception was raised. Basically:

m onException n = liftT m catch \e -> liftT n >> throw e

onException' Source

Arguments

:: MonadCatch m 
=> m a

Computation that may raise exception

-> m b

The computation to run if an exception is raised

-> m a 

Same as onException, but uses catch' and so second computation is executed if any exception is raised.

Utilities

bracket Source

Arguments

:: (Exception e, MonadMask m) 
=> m a

Computation to run before

-> (a -> m b)

Computation to run after

-> (a -> Throws e m c)

Computation to run in-between

-> Throws e m c

Result of the in-between computation

Run computation surrounded by acquire and release computations. The release computation is executed even if "in-between" computation raises exception. See also bracket', bracket_, bracketOnError, and bracketOnError'.

bracket' Source

Arguments

:: MonadMask m 
=> m a

Computation to run before

-> (a -> m b)

Computation to run after

-> (a -> m c)

Computation to run in-between

-> m c

Result of the in-between computation

Run computation surrounded by acquire and release computations. The release computation is executed even if "in-between" computation raises exception. See also bracket, bracket_, bracketOnError, and bracketOnError'.

Implementated as:

bracket' acq rel go = mask' $ \restore -> do
    x <- acq
    r <- restore (go x) `onException'` rel x
    _ <- rel x
    return r

bracket_ Source

Arguments

:: (Exception e, MonadMask m) 
=> m a

Computation to run before

-> m b

Computation to run after

-> Throws e m c

Computation to run in-between

-> Throws e m c

Result of the in-between computation

Variant of bracket.

Implemented as:

bracket_ acq rel go = bracket acq (const rel) (const go)

bracketOnError Source

Arguments

:: (Exception e, MonadMask m) 
=> m a

Computation to run before

-> (a -> m b)

Computation to run after if an exception was raised

-> (a -> Throws e m c)

Computation to run in-between

-> Throws e m c

Result of the in-between computation

Version of bracket where "after" computation is executed only if "in-between" computation raises exception.

Implemented as:

bracketOnError acq rel go = mask $ \restore -> do
    x <- liftT acq
    restore (go x) `onException` rel x

bracketOnError' Source

Arguments

:: MonadMask m 
=> m a

Computation to run before

-> (a -> m b)

Computation to run after if an exception was raised

-> (a -> m c)

Computation to run in-between

-> m c

Result of the in-between computation

Version of bracket where "after" computation is executed only if "in-between" computation raises exception.

Implemented as:

bracketOnError' acq rel go = mask' $ \restore -> do
    x <- liftT acq
    restore (go x) `onException'` rel x

finally Source

Arguments

:: (Exception e, MonadMask m) 
=> Throws e m a

Computation to run first

-> m b

Computation to run afterward (even if exception e was raised)

-> Throws e m a

Returns the result of the first computation

Run computation afeter another even if exception was thrown. See also finally', onException and onException'.

Implemented as:

m `finally` n = mask $ \restore -> do
    r <- restore m `onException` n
    _ <- liftT n
    return r

finally' Source

Arguments

:: MonadMask m 
=> m a

Computation to run first

-> m b

Computation to run afterward (even if some exception was raised)

-> m a

Returns the result of the first computation

Run computation afeter another even if exception was thrown. See also finally, onException and onException'.

Exception tag

data Throws e m a Source

Exception tag.

Instances

(Monoid w, MonadReader r m, MonadWriter w m, MonadState s m) => MonadRWS r w s (Throws k * e m) Source

Since 2.1.0.0

MonadError e m => MonadError e (Throws k * e' m) Source

Since 2.1.0.0

MonadReader r m => MonadReader r (Throws k * e m) Source

Since 2.1.0.0

MonadState s m => MonadState s (Throws k * e m) Source

Since 2.1.0.0

(Monoid w, MonadWriter w m) => MonadWriter w (Throws k * e m) Source

Since 2.1.0.0

MFunctor (Throws k * e) Source

Since 1.2.0.0.

MMonad (Throws k * e) Source

Since 1.2.0.0.

MonadTrans (Throws k * e) Source 
Monad m => Monad (Throws k * e m) Source 
Functor f => Functor (Throws k * e f) Source 
Applicative f => Applicative (Throws k * e f) Source 
Generic1 (Throws k * e m) Source 
Alternative f => Alternative (Throws k * e f) Source 
MonadPlus m => MonadPlus (Throws k * e m) Source 
MonadThrow m => MonadThrow (Throws k * e m) Source

Since 2.0.0.0.

MonadCatch m => MonadCatch (Throws k * e m) Source

Since 2.0.0.0.

MonadMask m => MonadMask (Throws k * e m) Source

Since 2.0.0.0.

MonadIO m => MonadIO (Throws k * e m) Source 
MonadCont m => MonadCont (Throws k * e m) Source

Since 2.1.0.0

Generic (Throws k k e m a) Source 
type Rep1 (Throws k k1 e m) Source 
type Rep (Throws k k1 e m a) Source 

Cobinators

liftT :: (Exception e, MonadThrow m) => m a -> Throws e m a Source

Construct exception tag, with type restrictions.

Reflect raised exception in function's type:

import Control.Monad.TaggedException (Throws, liftT)
import System.IO (Handle, IOMode)
import qualified System.IO as IO (openFile)


openFile :: FilePath -> IOMode -> Throws IOError IO Handle
openFile = (liftT .) . IO.openFile

Lifting m to Throws e m:

import Control.Exception (Exception)

import Control.Monad.TaggedException (Throws, liftT, throw)
import Data.Typeable (Typeable)


data EmptyString = EmptyString
    deriving (Show, Typeable)

instance Exception EmptyString

writeIfNotEmpty
    :: FilePath
    -> String
    -> Throws EmptyString IO ()
writeIfNotEmpty filename str = do
    when (null str) $ throw EmptyString
    liftT $ writeFile filename str

We have a some commonly used patterns:

(liftT .)
    :: (Exception e, MonadThrow m)
    => (a -> m b)
    -> a -> Throws e m b

Above is also usable for lifting throw-like functions:

import Control.Monad.Trans.Class (MonadTrans(lift))

((liftT . lift) .)
    ::  ( Exception e
        , MonadThrow m
        , MonadThrow (t m)
        , MonadTrans t)
    => (a -> m b)
    -> a -> Throws e (t m) b

lift2T :: (Exception e, Exception e', MonadThrow m) => m a -> Throws e' (Throws e m) a Source

Shorthand for liftT . liftT.

lift3T :: (Exception e, Exception e', Exception e'', MonadThrow m) => m a -> Throws e'' (Throws e' (Throws e m)) a Source

Shorthand for liftT . liftT . liftT.

liftT1 :: (Exception e, MonadThrow m) => (m a -> m b) -> Throws e m a -> Throws e m b Source

liftT for functions with arity one.

liftT2 :: (Exception e, MonadThrow m) => (m a -> m b -> m c) -> Throws e m a -> Throws e m b -> Throws e m c Source

liftT for functions with arity two.

liftT3 :: (Exception e, MonadThrow m) => (m a -> m b -> m c -> m d) -> Throws e m a -> Throws e m b -> Throws e m c -> Throws e m d Source

liftT for functions with arity three.

joinT :: (Exception e, MonadThrow m) => Throws e (Throws e m) a -> Throws e m a Source

Join two outermost exception tags.

joinT3 :: (Exception e, MonadThrow m) => Throws e (Throws e (Throws e m)) a -> Throws e m a Source

Join three outermost exception tags.

flipT :: (Exception e, Exception e', MonadThrow m) => Throws e' (Throws e m) a -> Throws e (Throws e' m) a Source

Flip two outermost exception tags.

insideT :: (Exception e, MonadThrow m, MonadThrow m') => (m a -> m' b) -> Throws e m a -> Throws e m' b Source

Generalized liftT. Usage examples:

insideT lift
   :: (MonadThrow (t m), MonadThrow m, Exception e, MonadTrans t)
   => Throws e m b
   -> Throws e (t m) b

This is variation on the first example that explicitly lifts monad:

insideT WriterT :: (Exception e, MonadThrow m, Monoid w) => Throws e m (b, w) -> Throws e (WriterT w m) b

Some useful compositions of exception tag combinators:

insideT flipT
    :: (Exception e0, Exception e1, Exception e2, MonadThrow m)
    => Throws e0 (Throws e1 (Throws e2 m)) a
    -> Throws e0 (Throws e2 (Throws e1 m)) a
flipT . insideT flipT
    :: (Exception e0, Exception e1, Exception e2, MonadThrow m)
    => Throws e0 (Throws e1 (Throws e2 m)) a
    -> Throws e2 (Throws e0 (Throws e1 m)) a

insideT2 :: (Exception e, MonadThrow m1, MonadThrow m2, MonadThrow m3) => (m1 a -> m2 b -> m3 c) -> Throws e m1 a -> Throws e m2 b -> Throws e m3 c Source

Generalized liftT2.

insideT3 :: (Exception e, MonadThrow m1, MonadThrow m2, MonadThrow m3, MonadThrow m4) => (m1 a -> m2 b -> m3 c -> m4 d) -> Throws e m1 a -> Throws e m2 b -> Throws e m3 c -> Throws e m4 d Source

Generalized liftT3.

insideTf :: (Exception e, Functor f, MonadThrow m, MonadThrow m') => (f (m a) -> m' b) -> f (Throws e m a) -> Throws e m' b Source

Variant of insideT.

Usage example:

insideTf StateT
    :: (Exception e, MonadThrow m)
    => (s -> Throws e m (a, s))
    -> Throws e (StateT s m) a

insideTf2 :: (Exception e, Functor f, Functor f', MonadThrow m, MonadThrow m') => (f (f' (m a)) -> m' b) -> f (f' (Throws e m a)) -> Throws e m' b Source

Variant of insideT.

Usage example:

insideTf2 RWST
    :: (Exception e, MonadThrow m)
    => (r -> s -> Throws e m (a, s, w))
    -> Throws e (RWST r w s m) a

embedT :: (Exception e, MonadThrow m, MonadThrow m') => (m a -> Throws e m' b) -> Throws e m a -> Throws e m' b Source

Since 1.2.0.0