generated at
StateモナドをIndexed Stateモナドにしていく
通常のMonadとIndexed Monad、
を比べて見る


通常のMonadの定義
hs
class Monad m where return :: a -> m a bind :: m a -> (a -> m b) -> m b
Indexed Monadの定義
hs
class IxMonad md where ireturn :: a -> md i i a ibind :: md i j a -> (a -> md j k b) -> md i k b
通常のMonadは、IxMonadで表現することができる
IxMonadはMonadの一般化なので。
hs
newtype M m p q a = M { unM:: m a } instance Monad m => IxMonad (M m) where ireturn = M . return ibind (M m) f = M (m >>= unM . f)





通常のState Monadの使用例
状態の初期値に0を取って、内部で1増やしている
hs
test1 :: (Int, Int) test1 = runState c 0 where c = do v <- get put $ succ v return v -- (0, 1)


doの糖衣構文を解く
上の test1 をdoを使わずに書く
hs
test1' :: (Int, Int) test1' = runState c 0 where c = get `bind` ( \v -> put (succ v) `bind` ( \_ -> return v)) -- (0, 1)



Indexed Monadを使って通常のState Monadを使用する
IxMonad で作ったStateモナド用に、 iget iput を定義しておく
hs
iget :: (MonadState s m) => M m s s s iget = M get iput :: (MonadState s m) => s -> M m s s () iput = M . put
通常のStateモナドの使用例を、IxMonadを使って書いている
hs
test2 :: (Int, Int) test2 = runState (unM c) 0 where c = iget `ibind` ( \v -> iput (succ v) `ibind` ( \_ -> ireturn v)) -- (0, 1)
do なしで書いた test1' にそっくりであることがわかる
IxMonadは、Monadの一般化なので、
このように通常のStateモナドもIxMonadを使って表現することができる








通常のStateTとmethodの定義
hs
newtype StateT s m v = StateT { runStateT :: s -> m (v,s) } instance (Monad m) => Monad (StateT s m) where return x = StateT $ \s -> return (x, s) bind m f = StateT $ \s -> do (x, s') <- runStateT m s runStateT (f x) s' get :: (Monad m) => StateT s m s get = state $ \s -> (s, s) put :: (Monad m) => s -> StateT s m () put s = state $ \_ -> ((), s)
bind の型は、
StateT s m a -> (a -> StateT s m b) -> StateT s m b
actionの実行前後で、Stateの型は変わらず s である

Indexed Monadを使ってStateTを定義する
hs
newtype IxStateT m si so v = IxStateT { runIxStateT:: si -> m (v, so) } instance Monad m => IxMonad (IxStateT m) where ireturn x = IxStateT $ \si -> return (x, si) ibind (IxStateT m) f = IxStateT $ \si -> do (x, so) <- m si runIxStateT (f x) so iget :: Monad m => IxStateT m si si si iget = IxStateT (\si -> return (si,si)) iput :: Monad m => so -> IxStateT m si so () iput s = IxStateT $ \_ -> return ((), s)
ibind の型は、
IxStateT m p q a -> (a -> IxStateT m q r b) -> IxStateT m p r b
iget の型は、 IxStateT m si si si
igetしても、IxStateTが管理する状態は変わらないので、 si のまま
iput の型は、 so -> IxStateT m si so ()
so iput することで、 IxStateT の管理する状態は、 si から so に変わる



Indexed State Monadの使用例
test2 を、IxStateTを使って書く
hs
test3 :: IO () test3 = runIxStateT c 0 >>= print where c = iget `ibind` ( \v -> iput (succ v) `ibind` ( \_ -> ireturn v)) -- (0,1)
特に嬉しさもない、ただの比較のためのコードmrsekut



IxStateの嬉しさの例
状態の初期値に0を取って、内部で1増やして、文字列に変換している
hs
test4 :: IO () test4 = runIxStateT c 0 >>= print where c = iget `ibind` ( \v -> iput (show $ succ v) `ibind` ( \_ -> ireturn v)) -- (0, "1")
RebindableSyntax 拡張を使って、doで見やすく書くと
hs
{-# LANGUAGE RebindableSyntax #-} ... test4' :: IO () test4' = runIxStateT c 0 >>= print where c = do v <- iget iput $ show $ succ v return v






参考