モナドも、コモナドも、あるんだよ(前篇)
さて、今回はみんな大好きなモナドだよ、まあ俺もそうだけど。
はendofunctor*1。今私たちの手元にmorphisms がある。問題は:どんな状況の下で、の意味を変更する事により、が別の圏にのような形式になるのか?
まず、何らかの方法で二つのmorphisms とをのような形式に「結合」しなければならない。そして、この「結合」は圏のcompositionの定義を満足しなければならない。最後、を圏のidとして存在しなければならない。
この新しい圏はKleisli categoryと言い、と表記される。の構成は下記通り:
のobject 元の圏のobject のmorphism 元の圏のmorphism *2 とはnatural transformation:
あと、compositionの結合則とidの定義を満足するために、とが下記の法則を従わなければならない:
1、
2、法則1はcompositionの結合則を保証する:
(in lhs: naturality )
()法則2は圏におけるidの定義を保証する:
(naturality )
()
monadクラスの定義:
class Monad m where (>>=) :: m a -> (a -> m b) -> m b return :: a -> m aと、関数joinの定義:
join :: (Monad m) => m (m a) -> m aこりゃ一目で分かるっしょ:
join <=>
return <=>それなら >>= は何ぞ?圏論のmonad定義でmonadはtripleであり、tripleの中にがあるのことを注目しよう。つまり、monadはfunctorである。
functorクラスの定義:class Functor where fmap :: (a -> b) -> f a -> f bfmap と >>= の定義が似てると思わない?ここで >>= の引数の順番をひっくり返してみよう:
(>>=改) :: (a -> m b) -> m a -> m bちょっと違うな…もし >>= が fmap なら最後の結果はm bじゃなくm (m b)でしょう?えっ?m (m b)とm b?その通り、必要なものはjoinだ。
つまり:x >>= f = join . (fmap f) $ xそして:
join . fmap f <=>
は何かを似てると思わない?そう、Kleisli categoryのcomposition。実際、Haskellもこのような演算子を定義している:
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c) f >=> g = \x -> f x >>= g>>= を展開すると:
f >=> g = \x -> join . (fmap g) . f $ xjoin . fmap g . f <=>
完全に一致。
次はhaskellのモナド則を検証してみよう:return >>= f == f -- 1 m >>= return == m -- 2 m >>= (\x -> f x >>= g) == (m >>= f) >>= g -- 3
- 1
return >>= f == f
= join . fmap f . return == f
= join . return . f == f
= join . return == id (when f = id)<=>
- 2
m >>= return == m
= join . fmap return $ m == m
= join . fmap return == id<=>
- 3
m >>= (\x -> f x >>= g) == (m >>= f) >>= g
= m >>= (f >=> g) == (m >>= return >>= f) >>= g
= m >>= h >>= (f >=> g) == m >>= (h >=> f) >>= g ( where h = return )
= m >>= (h >=> (f >=> g)) == m >>= ((h >=> f) >=> g)
= h >=> (f >=> g) == (h >=> f) >=> g<=>またしても完全に一致。
以上の考察により、圏論とHaskellのモナドは全く同じものと言っても良いだろう。しかし、Haskellはjoinではなく>>=演算子をMonadクラスのインタフェースとして定義した。まあ実用の面から考えたら当然だが、結果としてjoinの存在感が薄くなり、初心者にとって空気のような存在になるとかならないとか。joinの重要性に対してこのような扱いはあまりにも不憫しすぎだろう…
結論:joinは犠牲になったのた…>>=の犠牲にな…
(多分つづく)
追記:後篇
参考資料:
Dyads, a generalisation of monads, 1994, Maarten M. Fokkinga http://wwwhome.ewi.utwente.nl/~fokkinga/mmf94c.pdf