IORefとSTRefの使い分け
どうすればいい?
この心を理解していきたい
STRefとは
「状態の書き換え」をするだけで、IOには関わらない
code:hs
newSTRef :: a -> GHC.ST.ST s (STRef s a)
readSTRef :: STRef s a -> GHC.ST.ST s a
writeSTRef :: STRef s a -> a -> GHC.ST.ST s ()
modifySTRef :: STRef s a -> (a -> a) -> ST s ()
runST :: (forall s. ST s a) -> a
この辺の関数は全てSTモナドを返すので、runSTを使って値を取り出す
Stateモナドと異なり、複数の状態を扱うことができると見なせる
「計算」を状態として保持する
IORefとは
code:hs
newIORef :: a -> IO (IORef a)
writeIORef :: IORef a -> a -> IO ()
readIORef :: IORef a -> IO a
modifyIORef :: IORef a -> (a -> a) -> IO ()
STRefよりもだいぶできることが多いのかな
具体的にはよくわからないが
「計算」以外の状態も保持することができる
つまり?
最小の例を比較してみる
code:hs
import Data.IORef
import Control.Monad.ST
import Data.STRef
io :: IO Integer
io = do
a <- newIORef 1
writeIORef a 2
return =<< readIORef a
st :: ST s Integer
st = do
a <- newSTRef 1
writeSTRef a 2
return =<< readSTRef a
main = do
print =<< io -- 2
print $ runST st -- 2
ioとstはほぼ同じ見た目をしているが、返す型が異なるのでmainの中での扱いも異なってくる
参考