A real-life example: If I'm in a good mood('good state'), when manager asks me about estimates, I give him a solid answer, but dares he to do that 3 times in a row, without some free snacks in between, my mood changes(I get to 'bad state') and the next 3 times he approaches I ask him not to disturb me with any of his nonsense.
Here's a log of my usual day:
[ Mood: Good, Patience: 3 ] -- 11:00 am, I'm happy
ESTIMATE -> "bla bla 6", [ Mood: Good, Patience: 2 ]
ESTIMATE -> "bla bla 1", [ Mood: Good, Patience: 1 ]
Cookies! -> "", [ Mood: Good, Patience: 3 again! ]
ESTIMATE -> "bla bla 7", [ Mood: Good, Patience: 2 ]
ESTIMATE -> "bla bla 2", [ Mood: Good, Patience: 1 ]
ESTIMATE -> "bla bla 9", [ Mood: BAD , Patience: -2 ] -- Enough!
ESTIMATE -> "Need a break!" [ Mood: BAD , Patience: -1 ]
ESTIMATE -> "Deploynig!", [ Mood: BAD , Patience: 0 ]
ESTIMATE -> "Lunch time!", [ Mood: Good, Patience: 3 ] -- Ok he needs me..
ESTIMATE -> "bla bla 6", [ Mood: Good, Patience: 2 ]
...
Now this model of me at work seems to fit the State
Monad.
newtype State s a = State { runState :: s -> (a, s) }
But how do I do this? The signature has room for a state, which in my case is (Mood,Patience)
, and not for input (ESTIMATE
or Cookies
). It's like I'm supposed to answer without even listening!
So my question is: How do I make not only Stateful but also Argumentful computation with State
monad of Haskell?
A stateful computation gets an input, a state and returns an output and a new state. So the type will be
input -> state -> (state, output)
.The
runState
is just a partially applied stateful computation that has already taken its inputs.Note also that when you compose stateful functions (i.e. when you use the
>>=
bind operator ordo
notation) you do exactly this: you supply the inputs as expression and the bind is responsible for passing around only the state.You can call
get
without using its return value, but then it gets lost. If you want to make use of it you have to usevalue <- get
and then provide thevalue
as an explicit input for the next stateful computation. The bind only comes into play when passing the state around.Practical example: consider the function:
The
doStuff
type has exactly the patterninput -> state -> (state, output)
. But theinput
part is represented by thex
argument. Once you providex
you get something of typestate -> (state, output)
which is exactly whatrunState
represents.So you don't actually need the arguments for stateful actions because you can partially apply them beforehand to obtain "pure stateful computations that have no input" (those are scary quotes).
It sounds like what you're looking for is not
State
butStateT
, a monad transformer that adds statefulness to an existing monad.Given a state of type
s
, aStateT s m a
action returns anm
action that, when run, produces a result and a new state.StateT s
is an instance ofMonadTrans
:Further, if
m
is aMonad
, then so isStateT s m
.So if you want to take "input" within some context (e.g.,
IO
), you are free to do so:For
IO
in particular, it's usually better to useliftIO
, which can lift through a whole stack of transformers.