諸君 私はモナドが好きだ
諸君 私はモナドが好きだ
諸君 私はモナドが大好きだ
随伴対が好きだ
Kleisli圏が好きだ
EM圏が好きだ
あるF代数からの忘却関手の随伴に Freeモナドが現れたときなど心がおどる
「モナド!!モナド!!モナド!!」
よろしい ならばモナドだ
というわけで、今後モナドに関わる話をする準備としてまずは必要な関数の整理をしておきます。
「モナドとは何か」という話はしません。ごめんね。
(以下、型に現れる m
はモナドを表すことにしていちいち Monad m
は書きません)
モナドの基本関数
Haskell でモナドを扱うときには基本的に2つの関数
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a
を使います。
しかしモナド則の確認などのときは (>>=)
よりも join
という関数を使う方が簡単なことが多いのでその join
を紹介しましょう。
join
の (>>=)
を使っての定義は以下のとおりです。
join :: m (m a) -> m a
join m = m >>= id
型が示すとおり2重にモナドに包まれた値から1重にモナドに包まれた値を作りだす関数です。
有名なモナドの join
いくつか有名なモナドでの join
を (>>=)
を使わずに書いてみると
- リストモナド
join :: [[a]] -> [a]
join xss = concat xss
- Readerモナド
join :: (r -> (r -> a)) -> r -> a
join f r = f r r
- Writerモナド(
w
にモノイド制約が必要ですがその記述は省略します。Writer
のような構築子も省略してます)
join :: ((a, w), w) -> (a, w)
join ((a, x), y) = (a, x `mappend` y)
- Stateモナド(
State
のような構築子は省略してます)
join :: (s -> (s, s -> (s, a))) -> s -> (s, a)
join f s = let (s', f') = f s in f' s'
などとなります。
return, (>>=), fmap, join, id の絡み合い
先ほど join
を (>>=)
と id
を使って書きましたが、モナドでの fmap
も (>>=)
と return
を使って書くことができます。
fmap :: (a -> b) -> m a -> m b
fmap f m = m >>= (return . f)
逆に join
と fmap
を使って (>>=)
を書くこともできます。
(>>=) :: m a -> (a -> m b) -> m b
m >>= f = join (fmap f m)
モナド則
モナド三則を join
と return
と fmap
を使って書くと
join (return m) == m
join (fmap return m) == m
join (join m) == join (fmap join m)
となります。
3番目の法則は、外から内に向かって join
していっても、内から外に向かって join
していっても同じ値になるということを言っています。
具体的に
xss :: [[[Int]]]
xss = [ [ ], [ [1,2], [], [3] ], [ [4], [5], [6] ] ]
で確かめてみましょう。
join (join xss)
= join [ [1,2], [], [3], [4], [5], [6] ]
= [1,2,3,4,5,6]
join (fmap join xss)
= join [ join [], join [[1,2],[],[3]], join [[4],[5],[6]]]
= join [ [], [1,2,3], [4,5,6] ]
= [1,2,3,4,5,6]
よし。
May Monad be with you