Simple State monad step-by-step example.

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.

Tags: ,

Leave a Reply

Tips [+]