Idris2/libs/base/Control/Monad/Error/Interface.idr
2021-01-19 11:45:54 +01:00

154 lines
5.4 KiB
Idris

||| The Error monad (also called the Exception monad).
module Control.Monad.Error.Interface
-- module Control.Monad.Error.Class (
-- MonadError(..),
-- liftEither,
-- tryError,
-- withError,
-- handleError,
-- mapError,
-- ) where
--
||| The strategy of combining computations that can throw exceptions
||| by bypassing bound functions
||| from the point an exception is thrown to the point that it is handled.
||| Is parameterized over the type of error information and
||| the monad type constructor.
||| It is common to use `Either String` as the monad type constructor
||| for an error monad in which error descriptions take the form of strings.
||| In that case and many other common cases the resulting monad is already defined
||| as an instance of the 'MonadError' class.
public export
interface Monad m => MonadError e m | m where
||| Is used within a monadic computation to begin exception processing.
throwError : e -> m a
||| A handler function to handle previous errors and return to normal execution.
||| A common idiom is:
|||
||| ```idris example
||| do { action1; action2; action3 } `catchError` handler
||| ```
catchError : m a -> (e -> m a) -> m a
||| Lifts an `Either e` into any `MonadError e`.
public export
liftEither : MonadError e m => Either e a -> m a
liftEither = either throwError pure
||| Makes a success or failure of an action visible in
||| the return type.
public export
tryError : MonadError e m => m a -> m (Either e a)
tryError action = (map Right action) `catchError` (pure . Left)
||| `MonadError` analogue to the `withEitherT` function.
||| Modify the value (but not the type) of an error.
||| If you need to change the type of `e` use `mapError`.
public export
withError : MonadError e m => (e -> e) -> m a -> m a
withError f action = tryError action >>= either (throwError . f) pure
||| Flipped version of `catchError`.
public export
handleError : MonadError e m => (e -> m a) -> m a -> m a
handleError = flip catchError
||| `MonadError` analogue of the `mapEitherT` function. The
||| computation is unwrapped, a function is applied to the `Either`, and
||| the result is lifted into the second `MonadError` instance.
public export
mapError : (MonadError e m, MonadError e' n)
=> (m (Either e a) -> n (Either e' b)) -> m a -> n b
mapError f action = f (tryError action) >>= liftEither
--------------------------------------------------------------------------------
-- Implementations
--------------------------------------------------------------------------------
public export
MonadError () Maybe where
throwError () = Nothing
catchError Nothing f = f ()
catchError x _ = x
public export
MonadError e (Either e) where
throwError = Left
Left l `catchError` h = h l
Right r `catchError` _ = Right r
-- {- | @since 2.2 -}
-- instance Monad m => MonadError e (ExceptT e m) where
-- throwError = ExceptT.throwE
-- catchError = ExceptT.catchE
--
-- -- ---------------------------------------------------------------------------
-- -- Instances for other mtl transformers
-- --
-- -- All of these instances need UndecidableInstances,
-- -- because they do not satisfy the coverage condition.
--
-- instance MonadError e m => MonadError e (IdentityT m) where
-- throwError = lift . throwError
-- catchError = Identity.liftCatch catchError
--
-- instance MonadError e m => MonadError e (MaybeT m) where
-- throwError = lift . throwError
-- catchError = Maybe.liftCatch catchError
--
-- instance MonadError e m => MonadError e (ReaderT r m) where
-- throwError = lift . throwError
-- catchError = Reader.liftCatch catchError
--
-- instance (Monoid w, MonadError e m) => MonadError e (LazyRWS.RWST r w s m) where
-- throwError = lift . throwError
-- catchError = LazyRWS.liftCatch catchError
--
-- instance (Monoid w, MonadError e m) => MonadError e (StrictRWS.RWST r w s m) where
-- throwError = lift . throwError
-- catchError = StrictRWS.liftCatch catchError
--
-- instance MonadError e m => MonadError e (LazyState.StateT s m) where
-- throwError = lift . throwError
-- catchError = LazyState.liftCatch catchError
--
-- instance MonadError e m => MonadError e (StrictState.StateT s m) where
-- throwError = lift . throwError
-- catchError = StrictState.liftCatch catchError
--
-- instance (Monoid w, MonadError e m) => MonadError e (LazyWriter.WriterT w m) where
-- throwError = lift . throwError
-- catchError = LazyWriter.liftCatch catchError
--
-- instance (Monoid w, MonadError e m) => MonadError e (StrictWriter.WriterT w m) where
-- throwError = lift . throwError
-- catchError = StrictWriter.liftCatch catchError
--
-- #if MIN_VERSION_transformers(0,5,6)
-- -- | @since 2.3
-- instance (Monoid w, MonadError e m) => MonadError e (CPSRWS.RWST r w s m) where
-- throwError = lift . throwError
-- catchError = CPSRWS.liftCatch catchError
--
-- -- | @since 2.3
-- instance (Monoid w, MonadError e m) => MonadError e (CPSWriter.WriterT w m) where
-- throwError = lift . throwError
-- catchError = CPSWriter.liftCatch catchError
-- #endif
--
-- #if MIN_VERSION_transformers(0,5,3)
-- -- | @since 2.3
-- instance
-- ( Monoid w
-- , MonadError e m
-- #if !MIN_VERSION_base(4,8,0)
-- , Functor m
-- #endif
-- ) => MonadError e (AccumT w m) where
-- throwError = lift . throwError
-- catchError = Accum.liftCatch catchError
-- #endif
--