モナドも、コモナドも、あるんだよ(後篇)

前篇のつづき、コモナドを話す前にまずDualityについて復習しよう:

圏論にて、ある物の双対(Dual)を次のように定義する:

dual\hspace{5}A A
dual\hspace{5}x x
dual(f:\hspace{10}A\to B) dual\hspace{5}f:\hspace{10}B\to A
dual(f\hspace{5};\hspace{5}g) dual\hspace{5}g\hspace{5};\hspace{5}dual\hspace{5}f
dual(id{\tiny A}) id{\tiny A}

この定義はつまり確定的に明らかであること:矢印をひっくり返すだけ簡単な仕事です。

ある構造xxxに対して、中の要素をすべてdualをかけ、得た新し構造を圏論の言葉で言うとco-xxxである。

例:
ニート <=> コ会社員
全裸待機 <=> コ正装出撃
非リア <=> コリア充
など

???「これから毎日「コ」を付けろうぜ?」
(◕‿‿◕)「…わけがわからないよ」

まぁということで、モナドの定義をすべて対を取ればコモナドになるわけだ。

co-Kleisli category、\cal{K}^{op}は下記要素で構成される:

\cal{K}^{op}のobject a a
\cal{K}^{op}のmorphism g:\hspace{10}a\to{\tiny \cal{K}^{op}}b g:Ga\to b
f\hspace{5};{\tiny \cal{K}^{op}}\hspace{5}g \mu^{op}\hspace{5};\hspace{5}Gf\hspace{5};\hspace{5}g
id\tiny K^{op},Ga \eta^{op}\tiny Ga

\mu^{op}\eta^{op} は:

\mu^{op}:\hspace{10}G\to GG
\eta^{op}:\hspace{10}G\to I

下記法則を従う:

\mu^{op}\hspace{5};\hspace{5}G\mu^{op}\hspace{10}=\hspace{10}\mu^{op}\hspace{5};\hspace{5}\mu^{op}G
\mu^{op}\hspace{5};\hspace{5}G\eta^{op}\hspace{10}=\hspace{10}\mu^{op}\hspace{5};\hspace{5}\eta^{op}G\hspace{10}=\hspace{10}idG

モナド(comonad)とはtriple(G,\hspace{5}\mu^{op},\hspace{5}\eta^{op})のこと。

GHCのコモナドhackageDBから配布されてる。定義を見てみよう:

class Functor w => Extend w where
  duplicate :: w a -> w (w a)

class Extend w => Comonad w where
  extract :: w a -> a

(=>=) :: Extend w => (w a -> b) -> (w b -> c) -> w a -> c

つまり:

duplicate <=> \mu^{op}
extract <=> \eta^{op}
(=>=) <=> ;{\tiny \cal{K}^{op}}

Haskellのコモナドは下記の法則を従わなければならない:

-- 1

f =>= extract   = f
extract =>= f   = f
(f =>= g) =>= h = f =>= (g =>= h)

-- あるいは

-- 2

extract . duplicate      = id
fmap extract . duplicate = id
duplicate . duplicate    = fmap duplicate . duplicate

1と2は同じなのは前篇で証明出来たので、略する。

以上、モナドとコモナドの全部でした。
結論:コモナド地味すぎ。