------------------------------------------------------------------------------
-- |
-- Module      : PhatSort.Monad.Trans.Error
-- Description : error monad transformer
-- Copyright   : Copyright (c) 2019-2023 Travis Cardwell
-- License     : MIT
------------------------------------------------------------------------------

module PhatSort.Monad.Trans.Error
  ( -- * ErrorT
    ErrorT
    -- * API
  , errorT
  , errorTE
  , lift
  , liftEither
  , liftEitherE
  , run
  , throw
  , throwE
  ) where

-- https://hackage.haskell.org/package/base
import Control.Exception (Exception(displayException))
import Data.Bifunctor (first)

-- https://hackage.haskell.org/package/transformers
import qualified Control.Monad.Trans.Except as Except
import Control.Monad.Trans.Except (ExceptT(ExceptT))
import qualified Control.Monad.Trans.Class as Trans

------------------------------------------------------------------------------
-- $ErrorT

-- | Transformer used to manage errors: 'ExceptT' 'String'
--
-- @since 0.5.0.0
type ErrorT = ExceptT String

------------------------------------------------------------------------------
-- $API

-- | Manage 'String' errors of an action
--
-- @since 0.5.0.0
errorT
  :: Monad m
  => m (Either String a)
  -> ErrorT m a
errorT :: forall (m :: * -> *) a.
Monad m =>
m (Either String a) -> ErrorT m a
errorT = forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT
{-# INLINE errorT #-}

------------------------------------------------------------------------------

-- | Manage 'Exception' errors of an action
--
-- @since 0.5.0.0
errorTE
  :: (Exception e, Monad m)
  => m (Either e a)
  -> ErrorT m a
errorTE :: forall e (m :: * -> *) a.
(Exception e, Monad m) =>
m (Either e a) -> ErrorT m a
errorTE = forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first forall e. Exception e => e -> String
displayException)
{-# INLINE errorTE #-}

------------------------------------------------------------------------------

-- | Lift an action without errors
--
-- @since 0.5.0.0
lift
  :: Monad m
  => m a
  -> ErrorT m a
lift :: forall (m :: * -> *) a. Monad m => m a -> ErrorT m a
lift = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
Trans.lift
{-# INLINE lift #-}

------------------------------------------------------------------------------

-- | Manage 'String' errors
--
-- @since 0.5.0.0
liftEither
  :: Monad m
  => Either String a
  -> ErrorT m a
liftEither :: forall (m :: * -> *) a. Monad m => Either String a -> ErrorT m a
liftEither = forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a. Applicative f => a -> f a
pure
{-# INLINE liftEither #-}

------------------------------------------------------------------------------

-- | Manage 'Exception' errors
--
-- @since 0.5.0.0
liftEitherE
  :: (Exception e, Monad m)
  => Either e a
  -> ErrorT m a
liftEitherE :: forall e (m :: * -> *) a.
(Exception e, Monad m) =>
Either e a -> ErrorT m a
liftEitherE = forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first forall e. Exception e => e -> String
displayException
{-# INLINE liftEitherE #-}

------------------------------------------------------------------------------

-- | Run the transformer
--
-- @since 0.5.0.0
run
  :: Monad m
  => ErrorT m a
  -> m (Either String a)
run :: forall (m :: * -> *) a.
Monad m =>
ErrorT m a -> m (Either String a)
run = forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
Except.runExceptT
{-# INLINE run #-}

------------------------------------------------------------------------------

-- | Throw a 'String' error
--
-- @since 0.5.0.0
throw
  :: Monad m
  => String
  -> ErrorT m a
throw :: forall (m :: * -> *) a. Monad m => String -> ErrorT m a
throw = forall (m :: * -> *) e a. Monad m => e -> ExceptT e m a
Except.throwE
{-# INLINE throw #-}

------------------------------------------------------------------------------

-- | Throw an 'Exception' error
--
-- @since 0.5.0.0
throwE
  :: (Exception e, Monad m)
  => e
  -> ErrorT m a
throwE :: forall e (m :: * -> *) a. (Exception e, Monad m) => e -> ErrorT m a
throwE = forall (m :: * -> *) e a. Monad m => e -> ExceptT e m a
Except.throwE forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e. Exception e => e -> String
displayException
{-# INLINE throwE #-}