| Prev: The IO monad | TOC: Contents | Next: The Reader monad |
| Computation type: | Computations which maintain state. |
|---|---|
| Binding strategy: | Binding threads a state parameter through the sequence of bound functions so that the same state value is never used twice, giving the illusion of in-place update. |
| Useful for: | Building computations from sequences of operations that require a shared state. |
| Zero and plus: | None. |
| Example type: | State st a |
A pure functional language cannot update values in place because it violates referential transparency. A common idiom to simulate such stateful computations is to "thread" a state parameter through a sequence of functions:
data MyType = MT Int Bool Char Int deriving Show
makeRandomValue :: StdGen -> (MyType, StdGen)
makeRandomValue g = let (n,g1) = randomR (1,100) g
(b,g2) = random g1
(c,g3) = randomR ('a','z') g2
(m,g4) = randomR (-n,n) g3
in (MT n b c m, g4)
|
This approach works, but such code can be error-prone, messy and difficult to maintain. The State monad hides the threading of the state parameter inside the binding operation, simultaneously making the code easier to write, easier to read and easier to modify.
The definition shown here uses multi-parameter type classes and funDeps, which are not standard Haskell 98. It is not necessary to fully understand these details to make use of the State monad.
newtype State s a = State { runState :: (s -> (a,s)) }
instance Monad (State s) where
return a = State $ \s -> (a,s)
(State x) >>= f = State $ \s -> let (v,s') = x s in runState (f v) s'
|
Values in the State monad are represented as transition functions from an
initial state to a (value,newState) pair and a new type definition
is provided to describe this construct: State s a
is the type of a value of type a inside the State monad with state
of type s.
The type constructor State s is an instance of the
Monad class. The return function simply
creates a state transition function which sets the value but leaves
the state unchanged. The binding operator creates a state
transition function that applies its right-hand argument to the
value and new state from its left-hand argument.
class MonadState m s | m -> s where
get :: m s
put :: s -> m ()
instance MonadState (State s) s where
get = State $ \s -> (s,s)
put s = State $ \_ -> ((),s)
|
The MonadState class provides a standard but very simple
interface for State monads. The get function retrieves
the state by copying it as the value. The put function
sets the state of the monad and does not yield a value.
There are many additional functions provide which perform more
complex computations built on top of get and put.
The most useful one is gets which retrieves a function
of the state. The others are listed in the
documentation for the State monad library.
A simple application of the State monad is to thread the random generator state through multiple calls to the generation function.
| Code available in example15.hs |
|---|
data MyType = MT Int Bool Char Int deriving Show
{- Using the State monad, we can define a function that returns
a random value and updates the random generator state at
the same time.
-}
getAny :: (Random a) => State StdGen a
getAny = do g <- get
(x,g') <- return $ random g
put g'
return x
-- similar to getAny, but it bounds the random value returned
getOne :: (Random a) => (a,a) -> State StdGen a
getOne bounds = do g <- get
(x,g') <- return $ randomR bounds g
put g'
return x
{- Using the State monad with StdGen as the state, we can build
random complex types without manually threading the
random generator states through the code.
-}
makeRandomValueST :: StdGen -> (MyType, StdGen)
makeRandomValueST = runState (do n <- getOne (1,100)
b <- getAny
c <- getOne ('a','z')
m <- getOne (-n,n)
return (MT n b c m))
|
| Prev: The IO monad | TOC: Contents | Next: The Reader monad |