Edited at

復習 モナド

More than 3 years have passed since last update.


はじめに

monad って一体なんなのって、象の絵がかいてある本とか、色々な所で色々なやり方で論じられていると思うので、適宜調べればいいと思うんですけど、やっぱり自分用のまとめも欲しい。とりあえずここに『復習 モナド』としてまとめておきます。


レジュメ


monad.hs

-- 射の合成

(.) :: ( b -> c) -> ( a -> b) -> ( a -> c)
(<=<) :: Monad m => ( b -> m c) -> ( a -> m b) -> ( a -> m c)
(=<=) :: Comonad w => (w b -> c) -> (w a -> b) -> (w a -> c)
(<<<) :: Category cat => cat b c -> cat a b -> cat a c

-- 関手
($) :: ( a -> b) -> ( a -> b)
map :: ( a -> b) -> ([a] -> [b])
(<$>) :: Functor f => ( a -> b) -> (f a -> f b)

-- Applicative
repeat :: a -> [a]
pure :: Applicative f => a -> f a
(<*>) :: Applicative f => f (a -> b) -> (f a -> f b)

-- Monad
fmap :: Functor f => (a -> b) -> (f a -> f b)
return :: Monad m => a -> m a
join :: Monad m => m (m a) -> m a
(=<<) :: Monad m => (a -> m b) -> (m a -> m b)

-- Comonad
fmap :: Functor f => (a -> b) -> (f a -> f b)
head :: [a] -> a
extract :: Comonad w => w a -> a
duplicate :: Comonad w => w a -> w (w a)
(<<=) :: Comonad w => (w a -> b) -> (w a -> w b)



合成と圏論

小さいプログラムを『合成 compose』して、大きなプログラムを作りたい。たとえば f :: Float -> Int という「関数」と g :: Int -> String という「関数」を組み合わせて、 (g . f) :: Float -> String という「関数」を作れる。

a -> b の a の方を『ドメイン domain』、 b の方を『余ドメイン codomain』と呼ぼう。関数 g のドメインと関数 f の余ドメインが両方とも Int だから、合成できることが分かる。

「関数」だけじゃなくて、「無限リストの処理」とか「副作用のある計算」みたいなプログラムでも同じことができる。こういった、ドメインと余ドメインを持っていて合成できるものを『射 morphism』、その全体を『圏 category』と呼ぶ。圏論は圏や射についての理論。

Haskellの (.) 演算子は関数の合成。同様に (<=<) 演算子はKleisli圏(後で出てきます)の射 (a -> m b) の合成。Haskellにはそのまま Category という名前の型クラスが定義されていて、 (<<<) 演算子はどの圏の射の合成にも使える、オールマイティーな演算子。逆向きの (>=>) や (>>>) という演算子もある。


関手とFunctor型クラス

2013年2月2日 内容が間違っているので修正

HaskellのFunctor型クラスの定義する fmap 関数は、リストのに対する map 関数を一般化したものだと思える。「関数 (a -> b)」を「コンテナ型の関数 (f a -> f b)」に変換してくれる関数を定義している。

関数の圏の対象からコンテナ型の関数の圏の対象への関数 a -> f a は『対象関数 object function』、Qiita内で圏論に言及するエントリのまとめ (2)関数からコンテナ型の関数への写像 (a -> b) → (f a -> f b) は『射関数 mapping function』にあたる。関手はこの2つの関数から成り立っている。(Functor型クラスでは射関数 fmap だけが定義されている)

『関手 functor』はには次の性質が成り立つ。


functor.hs

-- 合成の保存

functor (g <<< f) === functor g <<< functor f
-- 恒等射の保存
functor id === id

恒等射は他の射と合成しても何も変わらない射。


id.hs

id <<< f === f

g <<< id === g

よく分からないイメージ図。


a →【g】→ b

⇩ map

[a] →【map g】→ [b]

a →【g】→ b

⇩ fmap

f a →【fmap g】→ f b

(<$>) 演算子はfmapの別名で、(fmap f)(f <$>) は同じ。


どうやら時間切れのようだ……

続きはまた次回。