packages feed

grisette-0.7.0.0: src/Grisette/Lib/Control/Monad/Except.hs

{-# 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 #-}