前回、
ストリング図について紹介しました。
例として、ストリング図を使ってモナド則を視覚的に表して、
State
モナドのモナド則をストリング図の変形で証明しています。
しかし、State
モナドのような単純なケースでは、ストリング図のありがたみが
まだわからないかもしれません。
今回は、StateT
モナド変換子(Control.Monad.Trans.State.Lazyを参照)のモナド則を、
ストリング図で示してみます。
(あと、ちょっときれいな図を描けるようになりました。)
ストリング図でStateT
前回の記事で使ったState
モナドの定義を再掲します。
(証明を楽にするために、Monad
クラスの定義もHaskell標準のものからちょっと変えています。)
type G s = (->) s -- (s ->) と書きたいが、Haskellはこの書き方は不可
type F s = (,) s -- (s, ) 〃
newtype State s a = State { runState :: G s (F s a) }
-- State s a ~ Compose (G s) (F s) a
instance Monad (State s) where
pure = open >>> State
= runState -- :: State s (State s a) -> G s (F s (State s a))
join >>> fmap (fmap runState) -- :: G s (F s (State s a)) -> G s (F s (G s (F s a)))
>>> fmap close -- :: G s (F s (G s (F s a))) -> G s (F s a)
>>> State -- :: G s (F s a) -> State s a
open :: a -> G s (F s a) -- a -> (s -> (s, a))
= \s -> (s, a)
open a
close :: F s (G s a) -> a -- (s, s -> a) -> a
= f s close (s, f)
この流儀に沿って、StateT
を定義し直してみます。
嬉しいことに、State
モナドの定義からopen
とclose
を流用できます。
newtype StateT s m a = State { runState :: G s (m (F s a)) }
-- StateT s m a ~ (G s `Compose` m `Compose` F s) a
-- ~ s -> m (s, a)
instance Monad m => Monad (StateT s m) where
pure = open -- a -> G s (F s a)
>>> fmap pure -- G s (F s a) -> G s (m (F s a))
>>> StateT -- G s (m (F s a)) -> StateT s m a
= fmap runState -- :: StateT s m (StateT s m a) -> StateT s m (G s (m (F s a)))
join >>> runState -- :: StateT s m (G s (m (F s a))) -> G s (m (F s (G s (m (F s a)))))
>>> fmap (fmap close) -- :: G s (m (m (F s a)))
>>> fmap join -- :: G s (m (F s a))
>>> StateT -- :: G s (m (F s a)) -> StateT s m a
ちょっと複雑になってしまいましたが、ストリング図にこれらの定義を起こしてみましょう。
図の中で、変換されるモナドm
のpure
やjoin
と、
これから構成するStateT s m
のpure
やjoin
は、色をつけて区別しています。
さて、図が煩雑になってきたので、以降はラベルを省いて描いてしまいます。
特に、モナドのpure
,join
は、どちらもラベルのない丸記号○だけで済ますことにします。
つながっている線の本数が違うため、pure
とjoin
の区別をつけるのに困ることはないです。
この省略記法を使って、StateT
のモナドの定義を描き直すと、次のようになります。
StateT
のモナド則
StateT s m
のモナド則も、State
モナド同様に、
図をどんどん変形するだけでできてしまいます。
ここで、モナドm
がもつpure
とjoin
(オレンジの丸)は、
モナド則を満たしていることが前提にできます。
また、前回の記事同様、open
とclose
の関係も使います。
これらの変形を組み合わせれば、StateT s m
のモナド則も、
図を描いてそれを変形させていくことで証明できます。
他のモナド変換子は?
ここまで来ると、ReaderT
やWriterT
、ExceptT
といった、他のモナド変換子たちの
モナド則がどう証明できるかが気になるかと思います。
実のところ、StateT
のモナド則というのは、
ストリング図による証明が一番簡単なたぐいのモナド変換子でした。
ReaderT
やWriterT
が成り立っている事情を説明するには、もうひとつ道具が必要です。
次の記事でそれを解説するつもりです。乞うご期待。