Simple State monad step-by-step example.

May 29, 2008 15:34


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.

programming, haskell

Previous post Next post
Up