Reputation: 297
I was reading LYAHFG and I can't get around understanding state monad.
In the book, state monad is defined as
newtype State s a = State { runState :: s -> (a,s) }
instance Monad (State s) where
return x = State $ \s -> (x,s)
(State h) >>= f = State $ \s -> let (a, newState) = h s
(State g) = f a
in g newState
pop :: State Stack Int
pop = State $ \(x:xs) -> (x,xs)
push :: Int -> State Stack ()
push a = State $ \xs -> ((),a:xs)
stackManip :: State Stack Int
stackManip = do
push 3
a <- pop
pop
runState stackManip [5,8,2,1]
The book explains this by using a stack, where stack is the state and an element is the result.
My question particularty is how does runState stackManip [5,8,2,1]
work?
runState
takes one argument, that's fine but stackManip
doesn't take any argument. How does initial state [5,8,2,1]
gets picked up?
Upvotes: 1
Views: 118
Reputation: 532053
A value of type State
is just a (wrapped) function. The Monad
instance for State
"composes" those functions, rather than actually working directly with state. runState
simply "unwraps" the function, giving you something you can directly apply to an initial state.
Another way of looking at it is that runState
is an application operator, like ($)
. It applies a State
(i.e., a state transformer) to an initial state.
Let's start with evalState
, though, which just produces the result, not the new state.
head $ [1,2,3] -- 1
pop `evalState` [1,2,3] -- 1
runState
just gives you a tuple consisting of the result and the new state.
pop `runState` [1,2,3] -- (1,[2,3])
Upvotes: 2
Reputation: 33519
runState
takes two arguments actually. When you declare a record
newtype State s a = State { runState :: s -> (a, s) }
This defines the function runState
with the following signature:
runState :: State s a -> s -> (a, s)
runState (State run) = run
You get the s -> (a, s)
type alone when manipulating records explicitly (pattern-matching, construction, update):
pop = State { runState = \(x : s) -> (x, s) }
Upvotes: 6