generated at
STモナドとStateモナドのAPIの比較
内部実装はガン無視して、型と使用感の類似性を見たい



todos
IORefも加えると面白そう


samples
State.hs
stt :: State Integer () stt = do forM_ [1..10] $ \i -> do modify (+i) main :: IO () main = print $ runState stt 0 -- ((),55)
ST.hs
st :: 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.hs
newtype State s a = State { runState :: s -> (a, s) }
ST.hs
newtype ST s a = ST (State# s -> (# State# s, a #))
順序など細かい違いはあるがやっていることは同じ



モナドの定義
hs
instance 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'
hs
instance 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モナドといえる
この定義が、元の定義と全く等価になっているのか微妙に自信がないmrsekut
これで正しいなら割と良いものを書けたと思う





run
State.hs
runState :: s -> (a, s)
ST.hs
runST :: (forall s. ST s a) -> a



modify
State.hs
modify:: (s -> s) -> State s () modify f = state (\s -> ((), f s))
ST.hs
modifySTRef :: STRef s a -> (a -> a) -> ST s () modifySTRef ref f = writeSTRef ref . f =<< readSTRef ref



get
State.hs
get :: State s s get = state (\s -> (s, s))
ST.hs
readSTRef :: STRef s a -> ST s a readSTRef (STRef var#) = ST $ \s1# -> readMutVar# var# s1#