content: {-# LANGUAGE Trustworthy #-}
  
  -- |
  -- Module      :   Grisette.Lib.Control.Monad.Except
  -- Copyright   :   (c) Sirui Lu 2021-2024
  -- License     :   BSD-3-Clause (see the LICENSE file)
  --
  -- Maintainer  :   siruilu@cs.washington.edu
  -- Stability   :   Experimental
  -- Portability :   GHC only
  module Grisette.Lib.Control.Monad.Except
    ( -- * mrg* variants for operations in "Control.Monad.Except"
      mrgThrowError,
      mrgCatchError,
      mrgLiftEither,
      mrgTryError,
      mrgWithError,
      mrgHandleError,
      mrgMapError,
      mrgModifyError,
    )
  where
  
  import Control.Monad.Except (ExceptT, MonadError (catchError, throwError))
  import Grisette.Internal.Core.Data.Class.Mergeable (Mergeable)
  import Grisette.Internal.Core.Data.Class.TryMerge (TryMerge, tryMerge)
  import Grisette.Lib.Control.Monad (mrgReturn)
  import Grisette.Lib.Control.Monad.Trans.Except (mrgRunExceptT)
  import Grisette.Lib.Data.Functor (mrgFmap)
  
  -- | 'Control.Monad.Except.throwError' with 'Grisette.Core.MergingStrategy'
  -- knowledge propagation.
  mrgThrowError :: (MonadError e m, TryMerge m, Mergeable a) => e -> m a
  mrgThrowError = tryMerge . throwError
  {-# INLINE mrgThrowError #-}
  
  -- | 'Control.Monad.Except.catchError' with 'Grisette.Core.MergingStrategy'
  -- knowledge propagation.
  mrgCatchError ::
    (MonadError e m, TryMerge m, Mergeable a) =>
    m a ->
    (e -> m a) ->
    m a
  mrgCatchError v handler = tryMerge $ v `catchError` (tryMerge . handler)
  {-# INLINE mrgCatchError #-}
  
  -- | 'Control.Monad.Except.liftEither' with 'Grisette.Core.MergingStrategy'
  -- knowledge propagation.
  mrgLiftEither ::
    (MonadError e m, TryMerge m, Mergeable a, Mergeable e) => Either e a -> m a
  mrgLiftEither = either mrgThrowError mrgReturn
  {-# INLINE mrgLiftEither #-}
  
  -- | 'Control.Monad.Except.tryError' with 'Grisette.Core.MergingStrategy'
  -- knowledge propagation.
  mrgTryError ::
    (MonadError e m, TryMerge m, Mergeable a, Mergeable e) =>
    m a ->
    m (Either e a)
  mrgTryError action = (mrgFmap Right action) `mrgCatchError` (mrgReturn . Left)
  {-# INLINE mrgTryError #-}
  
  -- | 'Control.Monad.Except.withError' with 'Grisette.Core.MergingStrategy'
  -- knowledge propagation.
  mrgWithError ::
    (MonadError e m, TryMerge m, Mergeable a, Mergeable e) =>
    (e -> e) ->
    m a ->
    m a
  mrgWithError f action =
    tryMerge $ mrgTryError action >>= either (mrgThrowError . f) mrgReturn
  {-# INLINE mrgWithError #-}
  
  -- | 'Control.Monad.Except.handleError' with 'Grisette.Core.MergingStrategy'
  -- knowledge propagation.
  mrgHandleError ::
    (MonadError e m, TryMerge m, Mergeable a, Mergeable e) =>
    (e -> m a) ->
    m a ->
    m a
  mrgHandleError = flip mrgCatchError
  {-# INLINE mrgHandleError #-}
  
  -- | 'Control.Monad.Except.mapError' with 'Grisette.Core.MergingStrategy'
  -- knowledge propagation.
  mrgMapError ::
    ( MonadError e m,
      TryMerge m,
      MonadError e' n,
      TryMerge n,
      Mergeable a,
      Mergeable b,
      Mergeable e,
      Mergeable e'
    ) =>
    (m (Either e a) -> n (Either e' b)) ->
    m a ->
    n b
  mrgMapError f action = tryMerge (f (mrgTryError action)) >>= mrgLiftEither
  {-# INLINE mrgMapError #-}
  
  -- | 'Control.Monad.Except.modifyError' with 'Grisette.Core.MergingStrategy'
  -- knowledge propagation.
  mrgModifyError ::
    ( MonadError e' m,
      TryMerge m,
      Mergeable a,
      Mergeable e,
      Mergeable e
    ) =>
    (e -> e') ->
    ExceptT e m a ->
    m a
  mrgModifyError f m =
    tryMerge $ mrgRunExceptT m >>= either (mrgThrowError . f) mrgReturn
  {-# INLINE mrgModifyError #-}
  