content: {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE GADTs #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# LANGUAGE MultiParamTypeClasses #-}
  {-# LANGUAGE TypeOperators #-}
  {-# LANGUAGE UndecidableInstances #-}
  
  -- | A church-encoded carrier for a 'Fresh' effect, providing access to a monotonically increasing stream of 'Int' values.
  --
  -- @since 1.1.0.0
  module Control.Carrier.Fresh.Church
  ( -- * Fresh carrier
    runFresh
  , evalFresh
  , FreshC(FreshC)
    -- * Fresh effect
  , module Control.Effect.Fresh
  ) where
  
  import Control.Algebra
  import Control.Applicative (Alternative)
  import Control.Carrier.State.Church
  import Control.Effect.Fresh
  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 'Fresh' effect counting up from 0.
  --
  -- @
  -- 'runFresh' k n ('pure' a) = k n a
  -- @
  -- @
  -- 'runFresh' k n 'fresh' = k (n '+' 1) n
  -- @
  --
  -- @since 1.1.0.0
  runFresh :: (Int -> a -> m b) -> Int -> FreshC m a -> m b
  runFresh k n = runState k n . runFreshC
  {-# INLINE runFresh #-}
  
  -- | Run a 'Fresh' effect counting up from an initial value, and forgetting the final value.
  --
  -- @
  -- 'evalFresh' n ('pure' a) = 'pure' a
  -- @
  -- @
  -- 'evalFresh' n 'fresh' = 'pure' n
  -- @
  --
  -- @since 1.1.0.0
  evalFresh :: Applicative m => Int -> FreshC m a -> m a
  evalFresh n = evalState n . runFreshC
  {-# INLINE evalFresh #-}
  
  -- | @since 1.1.0.0
  newtype FreshC m a = FreshC { runFreshC :: StateC Int m a }
    deriving (Alternative, Applicative, Functor, Monad, Fail.MonadFail, MonadFix, MonadIO, MonadPlus, MonadTrans)
  
  instance Algebra sig m => Algebra (Fresh :+: sig) (FreshC m) where
    alg hdl sig ctx = FreshC $ case sig of
      L Fresh -> state $ \ i -> (i + 1, i <$ ctx)
      R other -> alg (runFreshC . hdl) (R other) ctx
    {-# INLINE alg #-}
  