{-# LANGUAGE DeriveFunctor, ExplicitForAll, FlexibleContexts, FlexibleInstances, KindSignatures, MultiParamTypeClasses, TypeOperators, UndecidableInstances #-}
module Control.Effect.State.Lazy
( State (..)
, get
, gets
, put
, modify
, modifyLazy
, StateC(..)
, runState
, evalState
, execState
) where
import Control.Applicative (Alternative(..))
import Control.Effect.Carrier
import Control.Effect.Sum
import Control.Effect.State.Internal
import Control.Monad (MonadPlus(..))
import Control.Monad.Fail
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Prelude hiding (fail)
newtype StateC s m a = StateC { runStateC :: s -> m (s, a) }
instance Functor m => Functor (StateC s m) where
fmap f m = StateC $ \ s -> fmap (\ ~(s', a) -> (s', f a)) $ runStateC m s
{-# INLINE fmap #-}
instance (Functor m, Monad m) => Applicative (StateC s m) where
pure a = StateC $ \ s -> pure (s, a)
{-# INLINE pure #-}
StateC mf <*> StateC mx = StateC $ \ s -> do
~(s', f) <- mf s
~(s'', x) <- mx s'
return (s'', f x)
{-# INLINE (<*>) #-}
m *> k = m >>= \_ -> k
{-# INLINE (*>) #-}
instance Monad m => Monad (StateC s m) where
m >>= k = StateC $ \ s -> do
~(s', a) <- runStateC m s
runStateC (k a) s'
{-# INLINE (>>=) #-}
instance (Alternative m, Monad m) => Alternative (StateC s m) where
empty = StateC (const empty)
{-# INLINE empty #-}
StateC l <|> StateC r = StateC (\ s -> l s <|> r s)
{-# INLINE (<|>) #-}
instance MonadFail m => MonadFail (StateC s m) where
fail s = StateC (const (fail s))
{-# INLINE fail #-}
instance MonadIO m => MonadIO (StateC s m) where
liftIO io = StateC (\ s -> (,) s <$> liftIO io)
{-# INLINE liftIO #-}
instance (Alternative m, Monad m) => MonadPlus (StateC s m)
instance MonadTrans (StateC s) where
lift m = StateC (\ s -> (,) s <$> m)
{-# INLINE lift #-}
instance (Carrier sig m, Effect sig) => Carrier (State s :+: sig) (StateC s m) where
eff (L (Get k)) = StateC (\ s -> runState s (k s))
eff (L (Put s k)) = StateC (\ _ -> runState s k)
eff (R other) = StateC (\ s -> eff (handle (s, ()) (uncurry runState) other))
{-# INLINE eff #-}
runState :: s -> StateC s m a -> m (s, a)
runState s c = runStateC c s
evalState :: forall s m a . Functor m => s -> StateC s m a -> m a
evalState s = fmap snd . runState s
execState :: forall s m a . Functor m => s -> StateC s m a -> m s
execState s = fmap fst . runState s