ストリング図でMonad再入門(2)

前回、 ストリング図について紹介しました。 例として、ストリング図を使ってモナド則を視覚的に表して、 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
  join =   runState              -- :: State s (State s a) -> G s (F s (State s a))
       >>> 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))
open a = \s -> (s, a)

close :: F s (G s a) -> a  -- (s, s -> a) -> a
close (s, f) = f s

この流儀に沿って、StateTを定義し直してみます。 嬉しいことに、Stateモナドの定義からopencloseを流用できます。

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
  
  join =   fmap runState     -- :: StateT s m (StateT s m a) -> StateT s m (G s (m (F s a)))
       >>> 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

ちょっと複雑になってしまいましたが、ストリング図にこれらの定義を起こしてみましょう。

StateTの定義
StateTのpure
StateTのjoin

図の中で、変換されるモナドmpurejoinと、 これから構成するStateT s mpurejoinは、色をつけて区別しています。

さて、図が煩雑になってきたので、以降はラベルを省いて描いてしまいます。

省略記法

特に、モナドのpure,joinは、どちらもラベルのない丸記号○だけで済ますことにします。 つながっている線の本数が違うため、purejoinの区別をつけるのに困ることはないです。

この省略記法を使って、StateTのモナドの定義を描き直すと、次のようになります。

省略記法でのStateTの定義

StateTのモナド則

StateT s mのモナド則も、Stateモナド同様に、 図をどんどん変形するだけでできてしまいます。

ここで、モナドmがもつpurejoin(オレンジの丸)は、 モナド則を満たしていることが前提にできます。

mのモナド則

また、前回の記事同様、opencloseの関係も使います。

openとclose

これらの変形を組み合わせれば、StateT s mのモナド則も、 図を描いてそれを変形させていくことで証明できます。

StateTのモナド則(左単位法則、右単位法則も同様)
StateTのモナド則(結合法則)

他のモナド変換子は?

ここまで来ると、ReaderTWriterTExceptTといった、他のモナド変換子たちの モナド則がどう証明できるかが気になるかと思います。

実のところ、StateTのモナド則というのは、 ストリング図による証明が一番簡単なたぐいのモナド変換子でした。 ReaderTWriterTが成り立っている事情を説明するには、もうひとつ道具が必要です。 次の記事でそれを解説するつもりです。乞うご期待。