content: {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# LANGUAGE MultiParamTypeClasses #-}
  {-# LANGUAGE TypeOperators #-}
  {-# LANGUAGE UndecidableInstances #-}
  {- | A carrier for a 'Throw' effect.
  
  @since 1.0.0.0
  -}
  module Control.Carrier.Throw.Either
  ( -- * Throw carrier
    runThrow
  , ThrowC(ThrowC)
    -- * Throw effect
  , module Control.Effect.Throw
  ) where
  
  import Control.Algebra
  import Control.Applicative (Alternative)
  import Control.Carrier.Error.Either
  import Control.Effect.Throw
  import Control.Monad (MonadPlus)
  import Control.Monad.Fail as Fail
  import Control.Monad.Fix
  import Control.Monad.IO.Class
  import Control.Monad.Trans.Class
  
  -- | Run a 'Throw' effect, returning failures in 'Left' and successful computations’ results in 'Right'.
  runThrow :: ThrowC e m a -> m (Either e a)
  runThrow (ThrowC m) = runError m
  {-# INLINE runThrow #-}
  
  -- | @since 1.0.0.0
  newtype ThrowC e m a = ThrowC { runThrowC :: ErrorC e m a }
    deriving (Alternative, Applicative, Functor, Monad, Fail.MonadFail, MonadFix, MonadIO, MonadPlus, MonadTrans)
  
  instance Algebra sig m => Algebra (Throw e :+: sig) (ThrowC e m) where
    alg hdl sig ctx = case sig of
      L (Throw e) -> ThrowC (throwError e)
      R other     -> ThrowC (alg (runThrowC . hdl) (R other) ctx)
    {-# INLINE alg #-}
  