STモナドとStateモナドのAPIの比較
内部実装はガン無視して、型と使用感の類似性を見たい
todos
IORefも加えると面白そう
samples
State.hsstt :: State Integer ()
stt = do
forM_ [1..10] $ \i -> do
modify (+i)
main :: IO ()
main = print $ runState stt 0 -- ((),55)
ST.hsst :: ST s Integer
st = do
n <- newSTRef 0
forM_ [1..10] $ \i -> do
modifySTRef n (+i)
readSTRef n
main :: IO ()
main = print $ runST st -- 55
状態の初期値は
Stateは、runの外部から与えている
STは、内部で生成している
型
State.hsnewtype State s a = State { runState :: s -> (a, s) }
ST.hsnewtype ST s a = ST (State# s -> (# State# s, a #))
順序など細かい違いはあるがやっていることは同じ
モナドの定義
hsinstance Monad (State s) where
return a = State $ \s -> (a,s)
(State x) >>= f = State $ \s ->
let (a,s') = x s
(State y) = f a
in y s'
hsinstance Monad (ST s) where
return a = ST $ \s -> (# s, a #)
(ST x) >>= f = ST $ \s ->
let (# s', a #) = x s
(ST y) = f a
in y s'
こうして比較すると、「引数と返り値で連鎖することで状態を表現している」点は同じであることがわかる
型上の表現が異なるだけで、関数の実体としてやっていることは全く同じ
STモナドは、メモリ割り当てを状態として捉えるStateモナドといえる
この定義が、元の定義と全く等価になっているのか微妙に自信がない

これで正しいなら割と良いものを書けたと思う
run
ST.hsrunST :: (forall s. ST s a) -> a
modify
State.hsmodify:: (s -> s) -> State s ()
modify f = state (\s -> ((), f s))
ST.hsmodifySTRef :: STRef s a -> (a -> a) -> ST s ()
modifySTRef ref f = writeSTRef ref . f =<< readSTRef ref
get
State.hsget :: State s s
get = state (\s -> (s, s))
ST.hsreadSTRef :: STRef s a -> ST s a
readSTRef (STRef var#) = ST $ \s1# -> readMutVar# var# s1#