Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confusion about StateT, State and MonadState

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
like image 939
hgiesel Avatar asked Apr 16 '17 15:04

hgiesel


Video Answer


2 Answers

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.

like image 51
duplode Avatar answered Oct 25 '22 10:10

duplode


State is for your normal state monad. This is the simplest of the three. (In some older tutorials, you may see use of the State constructor, but this has been replaced with the state function, because State s is now a type alias for StateT s Identity.)

StateT is the monad transformer for the State monad. It adds a layer of generality by allowing you to put an arbitrary monad inside the state. This is useful for simple parsers, which could use e.g. StateT [Token] Maybe Result to represent the parsing as a stateful operation that could fail.

MonadState generalizes the situation even farther. There is an instance Monad m => MonadState s (StateT s m), but there are also instances, like one that allows you to perform stateful operations on monad transformers of StateT. All basic state functions (get, set, modify, etc.) can be used with an instance of MonadState.

like image 35
zbw Avatar answered Oct 25 '22 09:10

zbw