逆状態モナド
Stateモナドは、Haskellの遅延評価とmodifyの前後で状態の型が変わらない性質のおかげで、値の伝わり方の順序を保ちつつ状態の伝わり方を逆順にした派生を作ることができる。
newtype Rstate s a = Rstate { runRstate :: s -> (a, s) }
instance Functor (Rstate s) where
fmap = liftM
instance Applicative (Rstate s) where
pure = return
(<*>) = ap
instance Monad (Rstate s) where
return = Rstate . (,)
x >>= f = Rstate $ \s0 ->
let (a, s2) = runRstate x s1
(b, s1) = runRstate (f a) s0
in (b, s2)
instance MonadState s (Rstate s) where
state = Rstate
まあそうなるだろうなという感じで動く。
>>> flip runRstate "" $ do
>>> modify (<> "Hello")
>>> modify (<> "World")
>>> modify (<> "!!!!!")
((),"!!!!!WorldHello")
ちょっと面白けど、そんなに奇妙な動きをしているわけではない。
おまけ
RstateT
的なモナドトランスフォーマーを作ることはできない。これはモナドのバインドでは前の束縛を参照することができないからだ。
instance Monad m => Monad (RstateT m s) where
x >>= f = RstateT $ \s0 -> do
(a, s2) <- runRstateT x s1 -- ここでs1が見えない
(b, s1) <- runRstateT (f a) s0
return (b, s2)
do構文を脱糖すれば、なぜ遅延評価をもってしても変数が見えないのかが分かる。
Rstate $ \s0 ->
runRstateT x s1 >>= \(a, s2) -> -- ここでs1が見えない
runRstateT (f a) s0 >>= \(b, s1) ->
return (b, s2)
Rstate
が実装できてRstateT
が実装できないのは妙な気がするので、どうにか工夫すれば実装できそうな気がしないでもない。