I'm looking to pass a State monad through the following functions:
e1 :: Int -> (Bool, Int)
e1 el
| el > 100 = (True, el)
| otherwise = (False, 0)
e2 :: Int -> (Bool, Int)
e2 el
| el > 200 = (True, el)
| otherwise = (False, 0)
e3 :: Int -> (Bool, Int)
e3 el
| el > 300 = (True, el)
| otherwise == (False, 0)
implementor :: State Bool Int
implementor = state e1 ...
main = do
print $ runState implementor 10
Currently runState
is passed an State s a
(implementor
) and a value (10), and then returning the tuple from e1
.
However I'd like to bind these operations together, such as:
state e1 >>= e2 >>= e3
e1
would pass its State Bool Int
to e2
, which would operate on the Int
(through el
), then pass it's resulting State Bool Int
to e3
which, again, would operate on the Int
in this incoming State.
I've found the instance of Monad State very confusing, following this guide:
instance Monad (State s) where
return :: state $ \s -> (s, a)--this is returning a State which contains function (s -> (s, a))
m >>= k = state $ \s -> let (a, s') = runState m s --?
in runState (k a) s'
I don't understand what this instance of bind is doing and how to use this to bind e1
, e2
and e3
together?
If you use state :: (s -> (a, s)) -> State s a
on e1
, you end up with a State Int Bool
:
state e1 :: State Int Bool
That is something that acts over a state (in this case an Int
) and yields a Bool
as a result of using that state. So if we want to use e1
, e2
and e3
after each other in a stateful computation, we could use them with do
-notation:
allThree :: State Int ()
allThree = do
firstBool <- state e1
secondBool <- state e2
thirdBool <- state e3
return thirdBool
However, if we ignore the first two Bool
s, we can just remove the bindings:
allThree :: State Int Bool
allThree = do
state e1
state e2
state e3
And now we can rewrite do
-notation with >>
and >>=
. We end up with
allThree :: State Int Bool
allThree = state e1 >> state e2 >> state e3
As for how this works, let's have a look at >>=
m >>= k = state $ \s -> let (a, s') = runState m s
in runState (k a)
And m >> k
is m >>= const k
. So let's check what state e1 >> state 2
does:
state e1 >> state e2
= state e1 >>= const (state e2)
= state $ \s -> let (a, s') = runState (state e1) s in runState (const (state e2) a) s'
-- simplify runState (state e1) s to e1 s
= state $ \s -> let (a, s') = e1 s in runState (const (state e2) a) s'
-- use "const"
= state $ \s -> let (a, s') = e1 s in runState (state e2) s'
-- again simplify runState (state e2) s' to e2 s'
= state $ \s -> let (a, s') = e1 s in e2 s'
Therefore, the following terms are the same:
stateful s = runState (state e1 >> state e2) s -- use above to show that
stateless s = let (_, s') = e1 s
in e2 s'
Now, why was I able to use change runState (state f)
to f
? Because the definition of State
is rather boring:
-- simplified, modern versions use a more sophisticated approach!
newtype State s a = State { runState :: s -> (a, s) }
That is, a State
ful action is something that takes a state and returns a new one along to the value. The state
function is thus rather simple:
state :: (s -> (a, s)) -> State s a
state = State
And since runState (State f)
is f
, runState (state f)
is also `f´.
Therefore, we could write the Monad
instance a little bit different:
instance Monad (State s) where
(State e1) >>= f = State e3
where
e3 s = let (a, s') = e s
(State e2) = f a
in e2 s'
Remember, >>=
expects a function that takes something and returns another action, whereas the >>
can be used to chain actions after each other.