content: {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# LANGUAGE MultiParamTypeClasses #-}
  {-# LANGUAGE TypeOperators #-}
  {-# LANGUAGE UndecidableInstances #-}
  
  {- | A carrier for an 'Empty' effect, indicating failure with a 'Nothing' value. Users that need access to an error message should use the 'Control.Effect.Fail.Fail' effect.
  
  Note that 'Empty' effects can, when they are the last effect in a stack, be interpreted directly to a 'Maybe' without a call to 'runEmpty'.
  
  @since 1.0.0.0
  -}
  
  module Control.Carrier.Empty.Maybe
  ( -- * Empty carrier
    runEmpty
  , evalEmpty
  , execEmpty
  , EmptyC(..)
    -- * Empty effect
  , module Control.Effect.Empty
  ) where
  
  import Control.Algebra
  import Control.Effect.Empty
  import Control.Monad.Fail as Fail
  import Control.Monad.Fix
  import Control.Monad.IO.Class
  import Control.Monad.Trans.Class
  import Control.Monad.Trans.Maybe
  import Data.Functor (void)
  import Data.Maybe (isJust)
  
  -- | Run an 'Empty' effect, returning 'Nothing' for empty computations, or 'Just' the result otherwise.
  --
  -- @
  -- 'runEmpty' 'empty' = 'pure' 'Nothing'
  -- @
  -- @
  -- 'runEmpty' ('pure' a) = 'pure' ('Just' a)
  -- @
  --
  -- @since 1.0.0.0
  runEmpty :: EmptyC m a -> m (Maybe a)
  runEmpty (EmptyC m) = runMaybeT m
  {-# INLINE runEmpty #-}
  
  -- | Run an 'Empty' effect, discarding its result.
  --
  -- This is convenient for using 'empty' to signal early returns without needing to know whether control exited normally or not.
  --
  -- @
  -- 'evalEmpty' = 'void' '.' 'runEmpty'
  -- @
  --
  -- @since 1.1.0.0
  evalEmpty :: Functor m => EmptyC m a -> m ()
  evalEmpty = void . runEmpty
  {-# INLINE evalEmpty #-}
  
  -- | Run an 'Empty' effect, replacing its result with a 'Bool' indicating whether control exited normally.
  --
  -- This is convenient for using 'empty' to signal early returns when all you need to know is whether control exited normally or not, and not what value it exited with.
  --
  -- @
  -- 'execEmpty' = 'fmap' 'isJust' '.' 'runEmpty'
  -- @
  -- @
  -- 'execEmpty' ('pure' a) = 'pure' 'True'
  -- @
  -- @
  -- 'execEmpty' 'empty' = 'pure' 'False'
  -- @
  --
  -- @since 1.1.0.0
  execEmpty :: Functor m => EmptyC m a -> m Bool
  execEmpty = fmap isJust . runEmpty
  {-# INLINE execEmpty #-}
  
  -- | @since 1.0.0.0
  newtype EmptyC m a = EmptyC (MaybeT m a)
    deriving (Algebra (Empty :+: sig), Applicative, Functor, Monad, MonadFix, MonadIO, MonadTrans)
  
  -- | 'EmptyC' passes 'Fail.MonadFail' operations along to the underlying monad @m@, rather than interpreting it as a synonym for 'empty' à la 'MaybeT'.
  instance Fail.MonadFail m => Fail.MonadFail (EmptyC m) where
    fail = lift . Fail.fail
    {-# INLINE fail #-}
  