To better understand State monad I have derived it step by step from do notation to it’s constructor form. So to keep the result I post it here.
This is executable Haskell. Save as haskell file & try to run execState tickN 5 for every tickN.
[-] View Code HASKELL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
module StRed where
import Control.Monad.State
{-- Just for reference.
-- | A parameterizable state monad where /s/ is the type of the state
-- to carry and /a/ is the type of the /return value/.
newtype State s a = State { runState :: s -> (a, s) }
instance Monad (State s) where
return a = State $ \s -> (a, s)
m >>= k = State $ \s -> let
(a, s') = runState m s
in runState (k a) s'
instance MonadState s (State s) where
get = State $ \s -> (s, s)
put s = State $ \_ -> ((), s)
--}
-- This monad is able to add one to its internal state.
tick :: State Int Int
tick = do n <- get
put (n+1)
return n
-- What follows is a derivation of this monad into its normal form.
-- Please note, that this derivation doesn't respect Haskell's order of evaluation.
tick1 :: State Int Int
tick1 = get >>= (\n -> put (n+1) >>= (\_ -> return n))
tick2 = (State (\s -> (s,s))) >>=
(\n -> (State (\_ -> ((), (n+1)))) >>=
(\_ -> (State (\p -> (n, p)))))
tick3 = (State (\s -> (s,s))) >>=
(\n -> (State (\q -> let
(a, q') = runState (State (\_ -> ((), (n+1)))) q
in runState ((\_ -> (State (\p -> (n, p)))) a) q')))
tick4 = (State (\s -> (s,s))) >>=
(\n -> (State (\q -> let
(a, q') = ((), (n+1))
in (n, q'))))
tick5 = (State (\s -> (s,s))) >>=
(\n -> (State (\_ -> (n, n+1))))
tick6 = State (\p -> let
(a, p') = runState (State (\s -> (s, s))) p
in runState ((\n -> (State (\_ -> (n, n+1)))) a) p')
tick7 = State (\p -> let
(a, p') = (p, p)
in (a, a+1))
tick8 = State (\p -> (p, p+1))
-- So, here you are. This monad contains function which returns current state,
-- and changes internal state by adding one. Exactly what we supposed.
-- Now, when you run it with execState it's easy to see how it works.
a = execState tick8 3
a1 = snd (runState tick8 3)
a2 = snd ((\p -> (p, p+1)) 3)
a3 = snd (3, 4)
a4 = 4
-- In fact, I think this monad is easy to write in tick8 form right from the beginning =)
Hope this would help someone.
--
Crossposted from
~~. Go to
original post for comments.