mini-1.6.2.0: src/Mini/Transformers/StateT.hs
{-# LANGUAGE TupleSections #-}
-- | Extend a monad with a modifiable environment
module Mini.Transformers.StateT (
-- * Type
StateT (
StateT
),
runStateT,
-- * Operations
get,
modify,
put,
) where
import Control.Applicative (
Alternative,
empty,
(<|>),
)
import Control.Monad (
ap,
liftM,
(>=>),
)
import Control.Monad.IO.Class (
MonadIO,
liftIO,
)
import Mini.Transformers.Class (
MonadTrans,
lift,
)
import Prelude (
Applicative,
Functor,
Monad,
MonadFail,
const,
fail,
fmap,
pure,
($),
(.),
(<$>),
(<*>),
(>>=),
)
-- Type
-- | A transformer with state /s/, inner monad /m/, return /a/
newtype StateT s m a = StateT
{ runStateT :: s -> m (a, s)
-- ^ Unwrap a transformer computation with an initial state
}
instance (Monad m) => Functor (StateT s m) where
fmap = liftM
instance (Monad m) => Applicative (StateT s m) where
pure a = StateT $ pure . (a,)
(<*>) = ap
instance (Monad m, Alternative m) => Alternative (StateT s m) where
empty = StateT $ const empty
m <|> n = StateT $ \s -> runStateT m s <|> runStateT n s
instance (Monad m) => Monad (StateT s m) where
m >>= k = StateT $ runStateT m >=> (\(a, s) -> runStateT (k a) s)
instance MonadTrans (StateT s) where
lift m = StateT $ \s -> (,s) <$> m
instance (MonadFail m) => MonadFail (StateT s m) where
fail = StateT . const . fail
instance (MonadIO m) => MonadIO (StateT s m) where
liftIO = lift . liftIO
-- Operations
-- | Fetch the current state
get :: (Monad m) => StateT s m s
get = StateT $ \s -> pure (s, s)
-- | Update the current state with an operation
modify :: (Monad m) => (s -> s) -> StateT s m ()
modify f = StateT $ pure . ((),) . f
-- | Overwrite the current state with a value
put :: (Monad m) => s -> StateT s m ()
put = StateT . const . pure . ((),)