Permalink
Fetching contributors…
Cannot retrieve contributors at this time
95 lines (82 sloc) 2.79 KB
-- | This module defines the `MonadError` type class and its instances.
module Control.Monad.Error.Class where
import Prelude
import Data.Maybe (Maybe(..))
import Data.Either (Either(..), either)
-- | The `MonadThrow` type class represents those monads which support errors via
-- | `throwError`, where `throwError e` halts, yielding the error `e`.
-- |
-- | An implementation is provided for `ExceptT`, and for other monad transformers
-- | defined in this library.
-- |
-- | Laws:
-- |
-- | - Left zero: `throwError e >>= f = throwError e`
-- |
class Monad m <= MonadThrow e m | m -> e where
throwError :: forall a. e -> m a
-- | The `MonadError` type class represents those monads which support catching
-- | errors.
-- |
-- | - `catchError x f` calls the error handler `f` if an error is thrown during the
-- | evaluation of `x`.
-- |
-- | An implementation is provided for `ExceptT`, and for other monad transformers
-- | defined in this library.
-- |
-- | Laws:
-- |
-- | - Catch: `catchError (throwError e) f = f e`
-- | - Pure: `catchError (pure a) f = pure a`
-- |
class MonadThrow e m <= MonadError e m | m -> e where
catchError :: forall a. m a -> (e -> m a) -> m a
-- | This function allows you to provide a predicate for selecting the
-- | exceptions that you're interested in, and handle only those exceptons.
-- | If the inner computation throws an exception, and the predicate returns
-- | Nothing, then the whole computation will still fail with that exception.
catchJust
:: forall e m a b
. MonadError e m
=> (e -> Maybe b) -- ^ Predicate to select exceptions
-> m a -- ^ Computation to run
-> (b -> m a) -- ^ Handler
-> m a
catchJust p act handler = catchError act handle
where
handle e =
case p e of
Nothing -> throwError e
Just b -> handler b
-- | Return `Right` if the given action succeeds, `Left` if it throws.
try
:: forall e m a
. MonadError e m
=> m a
-> m (Either e a)
try a = (Right <$> a) `catchError` (pure <<< Left)
instance monadThrowEither :: MonadThrow e (Either e) where
throwError = Left
instance monadErrorEither :: MonadError e (Either e) where
catchError (Left e) h = h e
catchError (Right x) _ = Right x
instance monadThrowMaybe :: MonadThrow Unit Maybe where
throwError = const Nothing
instance monadErrorMaybe :: MonadError Unit Maybe where
catchError Nothing f = f unit
catchError (Just a) _ = Just a
-- | Make sure that a resource is cleaned up in the event of an exception. The
-- | release action is called regardless of whether the body action throws or
-- | returns.
withResource
:: forall e m r a
. MonadError e m
=> m r
-> (r -> m Unit)
-> (r -> m a)
-> m a
withResource acquire release kleisli = do
resource <- acquire
result <- try $ kleisli resource
release resource
either throwError pure result