I'm utterly confused between
newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}
and
type State s = StateT s Identity
and
class Monad m => MonadState s m | m -> s
Once upon a time, there was a State
type:
-- Not the current definition.
newtype State s a = State {runState :: s -> (a, s)}
State s a
values are, in essence, functions that take a state and produce a result and an updated state. Suitable Functor
, Applicative
and Monad
instances make it possible to compose such functions in a more convenient manner, by making the tuple shuffling need to handle the (a, s)
output implicit. With the help of a handful basic of operations that manipulate the state...
get = State $ \s -> (s, s)
put s = State $ \_ -> ((), s)
... it is possible to avoid any mention of the underlying s -> (a, s)
type, and write code that feels stateful.
StateT s
is a monad transformer patterned after State s
:
newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}
This transformer adds the state processing capabilities described above atop a base monad, m
. It comes with Functor
, Applicative
and Monad
instances, as well as versions of get
and put
.
If m
, the base monad, in StateT s m
is Identity
, the dummy functor...
newtype Identity a = Identity {runIdentity :: a}
... we get something equivalent to plain old State s
. That being so, transformers defines State
as a synonym...
type State s = StateT s Identity
... rather than as a separate type.
As for MonadState
, it caters to two different needs. Firstly, we can use the monad transformers machinery to have StateT s m
as a base monad for some other transformer in a stack of transformers (arbitrary example: MaybeT (StateT Int IO)
). In that case, though, lift
from MonadTrans
becomes necessary to use get
and put
. One way of using the operations directly in such cases is through MonadState
: it provides them as methods...
-- Abridged class definition.
class Monad m => MonadState s m | m -> s where
get :: m s
put :: s -> m ()
state :: (s -> (a, s)) -> m a
... so that we can have instances for any combination of transformers involving StateT
that we are interested in.
instance Monad m => MonadState s (StateT s m) where -- etc.
instance MonadState s m => MonadState s (MaybeT m) where -- etc.
-- And so forth
Secondly, if we want to have a state monad with an implementation different than the one in transformers, we can make it an instance of MonadState
, so that we keep the same basic operations and, as long as we write type signatures in terms of MonadState
, have it easier to change implementations if need be.