Monad: State
This summary follows the minimum useable principle.
Readings
newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }
Simple definition from learn you a haskell
newtype State s a = State { runState :: s -> (a,s) }

Complete definition from Control.Monad.Trans
newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }
instance (Monad m) => Monad (StateT s m) where
return a = StateT $ \ s -> return (a, s)
m >>= k = StateT $ \ s -> do
~(a, s') <- runStateT m s
runStateT (k a) s'
fail str = StateT $ \ _ -> fail str
Self recap

Monadic Semantics
- Target type :
a - Context type :
State sorStateT s m- Explicitly : transformation among
target types. - Implicitly : Each computation produce new state information of type
sand pass to the following computation in the target types transformation.
- Explicitly : transformation among
- A function from
stoa.
s -> a
- Sometimes, the value of
swill be updated and could affect following computation, so the new value need to be preserved.
s -> (a,s)
- Now we have a new type
newtype State s a = State {runState ::s -> (a,s)}.- Two or more computations of type
a -> State s bcould be composed by>>=or>=>means each computation use the informationspassed by previous one. (There could be other compositions that use state of other computation in different ways.)
f >>= g :: s0 -> (a,s1) -> ( a -> s1 -> (b,s2)) -> (s0 -> (b,s2)
s0, s1, s2are values of the types.
Clearly,>>=and>=>chained these computations and hide the intermediate states1, produce a function betweens0ands2.
- auxiliary functions
get,put,return - each produce a State monad in different purposes
- these special purpose State monads are composed by
>>=and>>operator. - They collectively work as a single State Monad for certain function.
get
getthe current value of the state from previous State computation.
get :: (Monad m) => StateT s m s
get = state $ \ s -> (s, s)
put
putupdates the value ofs.
put :: (Monad m) => s -> StateT s m ()
put s = state $ \ _ -> ((), s)
return / pure
- combine the computation result
atogether with whateversis.
instance (Monad m) => Monad (StateT s m) where
return a = StateT $ \ s -> return (a, s)
>>=
m >>= k = StateT $ \ s -> do
~(a, s') <- runStateT m s
runStateT (k a) s'
summary
Use get to receive s from previous State computation, use put to update the value of s if necessary, and combine computation result a with s.
state
- turn a simple state style computation into State Monad
state :: (Monad m)
=> (s -> (a, s)) -- ^pure state transformer
-> StateT s m a -- ^equivalent state-passing computation
state f = StateT (return . f) -- this return is pair with m above.
runState
- Unwrap a state monad computation as a function.( The inverse of ‘state’.)
newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }
runState :: State s a -- ^state-passing computation to execute
-> s -- ^initial state
-> (a, s) -- ^return value and final state
runState m = runIdentity . runStateT m
evalStateT
- When we do not need the information in
sanymore. - Use
evalStateTorevalStateto get function of types -> m aors -> a
evalStateT
evalStateT :: (Monad m) => StateT s m a -> s -> m a
evalStateT m s = do
~(a, _) <- runStateT m s
return a
evalState :: State s a -- ^state-passing computation to execute
-> s -- ^initial value
-> a -- ^return value of the state computation
evalState m s = fst (runState m s)
{-# INLINE evalState #-}
Common usage
- use
getto introduce the state. (compulsory) - some pure function ::
s -> atransformstoa. (optional) returnwrapainto State Monad. (compulsory)putupdates the state. (optional, must followed by areturn)evaState/evalStateT
or
runState/runStateT
get the function of type:: s -> (a,s)wrapped inside. They each works slight differently. (compulsory)
5.1 runState / runStateT retrive functions-> (a,s)ors -> m (a,s)
5.2 evalState / evalStateT retrive functions -> aors -> m a- feed to initial state
s0into the functions -> (a,s)and get the final resultaand final states.
Intuition:
- State Monad wrap a function from type
sto an core outputaand new value of types. get,put,returneach represent Reader Monad of different specific purpose.- Usually, they composed (>>=) (>>) together to form a functional State Monad.
necessary import
-- | Imports before Example One
import Control.Monad.Trans.State
import Control.Monad -- for operator >=>
Example one
- In general . State Monad is a function, the output include an extra part of information that is of the same type of the input.
- The input of
>=> or >>=operation will always be the first one - the Initial state will also be the first one as well .
s1 :: Int -> State String Float
s1 i = do
s <- get
let
is = show i ++ "_"++ s
r = fromIntegral i / (fromIntegral . length) is
put is
return r
s2 :: Float -> State String String
s2 f = do
s <- get
let
sf = show f ++ "_"++ s
put sf
return sf
s3 :: String -> State String Int
s3 str = do
s <- get
let
ns = str ++ "_" ++ s
put ns
return $ length ns
sChainOne :: Int -> State String Int
sChainOne = s1 >=> s2 >=> s3
> :info sChainOne
sChainOne :: Int -> State String Int
> let sFunc = runState $ sChainOne 20
sFunc :: String -> (Int, String)
> let r = sFunc "emmettng"
> r
(43,"1.8181819_20_emmettng_1.8181819_20_emmettng")
Intuition:
State String Int
-
Explicitly
Int: Target Operations include:s1 :: Int -> Float,s2 :: Float -> String,s3 :: String -> Int- These transformation composed together as
Int -> Int
-
Implicitly
State String: Context Semantics:- There is an extra piece of information of type
Stringinvolved in these transformations. SO,s1 :: Int -> String -> Float. - Furthermore, the value of
Stringmight be updated and pass to the following function:s1 :: Int -> String (Float,String), so the same ass2ands3.
- There is an extra piece of information of type
-
return/pureis always about bring value oftarget typeinto thisComputation Context.