{-# LANGUAGE DeriveFunctor, ExistentialQuantification, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, StandaloneDeriving, TypeOperators, UndecidableInstances #-}
module Control.Effect.Fresh
( Fresh(..)
, fresh
, resetFresh
, runFresh
, FreshC(..)
) where
import Control.Applicative (Alternative(..))
import Control.Effect.Carrier
import Control.Effect.State
import Control.Effect.Sum
import Control.Monad (MonadPlus(..))
import Control.Monad.Fail
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
data Fresh m k
= Fresh (Int -> k)
| forall b . Reset (m b) (b -> k)
deriving instance Functor (Fresh m)
instance HFunctor Fresh where
hmap _ (Fresh k) = Fresh k
hmap f (Reset m k) = Reset (f m) k
instance Effect Fresh where
handle state handler (Fresh k) = Fresh (handler . (<$ state) . k)
handle state handler (Reset m k) = Reset (handler (m <$ state)) (handler . fmap k)
fresh :: (Member Fresh sig, Carrier sig m) => m Int
fresh = send (Fresh pure)
resetFresh :: (Member Fresh sig, Carrier sig m) => m a -> m a
resetFresh m = send (Reset m pure)
runFresh :: Functor m => FreshC m a -> m a
runFresh = evalState 0 . runFreshC
newtype FreshC m a = FreshC { runFreshC :: StateC Int m a }
deriving (Alternative, Applicative, Functor, Monad, MonadFail, MonadIO, MonadPlus, MonadTrans)
instance (Carrier sig m, Effect sig) => Carrier (Fresh :+: sig) (FreshC m) where
eff (L (Fresh k)) = FreshC $ do
i <- get
put (succ i)
runFreshC (k i)
eff (L (Reset m k)) = FreshC $ do
i <- get
a <- runFreshC m
put (i :: Int)
runFreshC (k a)
eff (R other) = FreshC (eff (R (handleCoercible other)))
{-# INLINE eff #-}