Reputation: 11
In the tutorial Learn You a Haskell - chapter 'for-a-few-monads-more', section 'The State monad', it lists the following to define the State Monad:
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
Just need an answer to a simple question: What would the input to \s be (since State h = a function that takes a state and outputs a tuple (result, newState); implying that input to \s would just be that function)? Examples welcome
Upvotes: 0
Views: 193
Reputation: 144206
You can think of a value of State s a
as being a computation which depends on some state parameter which is provided when the computation is run. You can do this by simply unwrapping the contained function and calling it e.g.
runState (return 1) "state"
=> (1, "state")
Upvotes: 2
Reputation: 532093
You can picture return x
as meaning "Give me a state, and I'll give you back that state and x". Then you can think of x >>= f1
as "Give me a state, and I'll give that to x
; once it returns a state and a value, I'll give those to f
and pass what f
gives me on to you."
Here's an analogy with function composition:
f, g, h :: a -> a
j = f . g . h :: a -> a
j
is a function that takes an a
, and returns an a
. Along the way, that value is first given to h
, whose output goes to g
, whose output goes to f
, whose output is returned.
Look at "composition" of functions that return State
values.
f', g', h' :: a -> State s a
j' a = return a >>= h' >>= g' >>= f'
Think of State
as being a way of "hiding" a function argument. You could compose them manually like this:
f'', g'', h'' :: a -> s -> (a, s)
-- We could make this point-free by leaving h curried, but this
-- is nicely consistent.
j'' a s = (uncurry f'') . (uncurry g'') . (uncurry h'') $ (a, s)
but the State
monad effectively does that for you with its implementation of >>=
.
Note that j'
only takes an initial value, while j''
takes an initial value and an initial state. That's because the function that would take that state for j'
is still wrapped up in a State
value; we use runState
to retrieve that function so that an initial state can be supplied to the first function in the stack.
(runState j') s0 -- parentheses optional, shown for emphasis
Upvotes: 1