はじめに
以下文書はどっちかというと現状のボクの認識を備忘録的にまとめているモノであって、他文書ほど第三者に読みやすい文章や前提とはなっていない可能性がある。
また、誤認や曖昧な言い回しも散見されるので、ご指摘があればコメントにていただければ幸いです
序論
Functor/Applicative/Monadを考察してみた場合、これら全体に言えることはまず型クラスであり具象の型ではない(従って、C#におけるInterfaceやRustにおけるTraitのように、いかなる関数を実装すべきかを提示はしているがその関数の実装に関しては何らの要請もしていない)
以下、カリー化を厳密に解釈すると引数は常に一つとはなるが、便宜のため左結合と解釈し、左側から第1引数..第n引数と呼称することにする。
Functor
Functorの定義は以下の通り。
class Functor f where
fmap :: (a -> b) -> f a -> f b
これはfmap関数により、第1引数によって提示された関数を文脈fでWrapされた第2引数に適用し、結果として文脈fでWrapされた値bを導出することになる。
実務としてはMaybeのような型に対して、内部の値を外に出すことなく処理して結果を文脈fにWrapして取得することが可能である。
Applicative
Applicativeの定義は以下の通り。
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
Functorとしてのtraitを持ちつつ、加えてpure関数と<*>演算子が定義されている。
pure関数は値aを文脈fの中に内包させる機能を持つ。
<*>演算子は左辺に提示された文脈fにWrapされた関数を右辺に適用してその結果を文脈fにWrapされた値bを返却する。
Monad
Monadの定義は以下の通り
class Applicative m => Monad m where
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
return :: a -> m a
Monadで特に重要な演算子は>>=となる。
MonadはこれまでのFunctor/Applicativeと異なり、左辺に文脈mにWrapされた値a、右辺に値aから文脈mにWrapされた値bを返却する関数を取り、結果として文脈mにWrapされた値bを返す。
ここで重要なのは左辺にm aを取ることから、>>=を連鎖的に適用することができる。これは結果的に順序を与えることになる。
また、歴史的な経緯からreturnが定義されているが、これはApplicativeのpureと同型であり、class Applicative m => Monadの定義通りMonadはApplicativeを包含しているのでpureを使うことが一般的である。
また、>>
演算子はm aを用いずにm bを生成しm bを返却する。
理解の追いついていない点
- Monad->Applicative->Functorという包含関係になっている理由
- Applicativeだと何がうれしいのか