Stateモナドを手で展開してみる

30分プログラム、その392。Stateモナドを理解するために手で展開してみた。
展開してみた感想は、確かにStateモナドが状態を持てる理由は分かった気がする。でも、これをモナドに押し込めた人は天才だと思う。

do 記法

とりあえず、普通に書いてみた。

import Control.Monad.State

inc :: State Int String
inc = do x <- get
         put $ x+1
         return $ show x

f = fst $ runState (do a <- inc
                       b <- inc
                       c <- inc
                       return (a,b,c)) 0

実行例:

*Main> f
(("0","1","2"),3)

>>=を使って書き直し

do記法は書きやすいけど、展開しずらい。なのでとりあえず、>>=を使って展開する。あえて>>は使わない。

import Control.Monad.State


inc2 :: State Int String
inc2 = get >>= 
       \x -> put (x + 1) >>= 
             \_ -> return (show x)

g = runState 
    (inc >>= 
             \a -> inc >>= 
                   \b -> inc >>= \c ->
                         return (a,b,c)) 0

全部自分の手で書き直した

定義を参考にして、手で展開してみた。そうとう大変だった。
どこか間違ってるかも。

get' s = (s,s)
put' s _ = ((),s)
return' a = \s -> (a,s)

inc3 :: Int -> (String,Int)
inc3 state = let (v,s') = get' state in
             (f v) s'
    where f x s = let (_,s') = put' (x+1) s in
                  (return' (show x)) s'

h state = let (a,s1) = inc3 state in
          (\s -> let (b,s2) = inc3 s in
                 (\s -> let (c,s3) = inc3 s in
                        (return' (a,b,c)) s3) s2) s1