Functor, Applicative, Monadのシンプルな定式化

HaskellとScalaのMonad関連について学び始めた頃に以下のブログ記事を読みました。

> [Functors, Monads, Applicatives – can be so simple | de.velopmind | The Det about Programming](https://thedet.wordpress.com/2012/04/28/functors-monads-applicatives-can-be-so-simple/)

Functor, Applicative, Monadといえば様々な角度やレベルから説明が可能と思われ、実際に多くの書籍や記事、ドキュメントで多くのことが語られていますが、このブログ記事は本質的な機能を(タイトル通り)とてもシンプルに説明していました。
直感的に理解しやすいと感じていたので、この内容を参考に補足説明とサンプルコードを加えて改めて整理してみました。
※**注意**: シンプルに抽象化して統一的に理解することを目的としているため、Scala, Haskellの実際の言語仕様や実装レベルの詳細に正確には一致しない部分があります。


# 定式化

型パラメータを取る型**C**の中身の型を**A**から**B**に変換するには**C[A] => C[B]**という型の関数が必要となる。
型**C**が`Functor`, `Applicative`, `Monad`のインスタンスであれば、以下の3通りの方法で関数**C[A] => C[B]**を得ることができる。

## 1. 型クラス`Functor`のコア機能

> **(A => B) => (C[A] => C[B])**

関数**A => B**を関数**C[A] => C[B]**に変換する。

| Scala |    Haskell    |
|:-----:|:-------------:|
| `map` | `fmap`, `<$>` |

## 2. 型クラス`Applicative`のコア機能

> **C[A => B] => (C[A] => C[B])**

関数**C[A => B]**を関数**C[A] => C[B]**に変換する。

| Scala (scalaz) | Haskell |
|:--------------:|:-------:|
| `ap`, `<*>`    | `<*>`   |

## 3. 型クラス`Monad`のコア機能

> **(A => C[B]) => (C[A] => C[B])**

関数**A => C[B]**を関数**C[A] => C[B]**に変換する。

|   Scala   | Haskell |
|:---------:|:-------:|
| `flatMap` | `>>=`   |


# 適用例

型**C**の具体例としてScalaの`Option`、Haskellの`Maybe`を当てはめてみる。

## 1. **A => B**という型の関数があるとき
型**C**が`Functor`のインスタンスであれば**C[A] => C[B]**が得られる。
例えば、

> **(Int => String) => (Option[Int] => Option[String])**

```scala:Scala
val f: Int => String = x => x.toString
val n: Option[Int] = Some(1)

// Option#map を利用すると
n.map(f)

// (OptionはMonadでもあるので) for式で書くと
for {
  a <- n
} yield f(a)
```

```hs:Haskell
f :: Int -> String
f = \x -> show x
n :: Maybe Int
n = Just 1

-- fmap を利用すると
fmap f n

-- <$> を利用すると
f <$> n

-- (MaybeはMonadでもあるので) do記法で書くと
do
  a <- n
  return $ f a
```

## 2. **C[A => B]**という型の関数があるとき

型**C**が`Applicative`のインスタンスであれば**C[A] => C[B]**が得られる。
例えば、

> **Option[Int => String] => (Option[Int] => Option[String])**

```scala:Scala
val f: Option[Int => String] = Some(x => x.toString)
val n: Option[Int] = Some(1)

import scalaz._, Scalaz._

// scalaz.Apply.ap を利用すると
Apply[Option].ap(n)(f)

// scalaz.syntax.ApplyOps.<*> を利用すると
n <*> f

// (OptionはMonadでもあるので) for式で書くと
for {
  a <- n
  g <- f
} yield g(a)
```

```hs:Haskell
f :: Maybe (Int -> String)
f = Just $ \x -> show x
n :: Maybe Int
n = Just 1

-- <*> を利用すると
f <*> n

-- (MaybeはMonadでもあるので) do記法で書くと
do
  a <- n
  g <- f
  return $ g a
```

## 3. **A => C[B]**という型の関数があるとき

型**C**が`Monad`のインスタンスであれば**C[A] => C[B]**が得られる。
例えば、

> **(Int => Option[String]) => (Option[Int] => Option[String])**

```scala:Scala
val f: Int => Option[String] = x => Some(x.toString)
val n: Option[Int] = Some(1)

// Option#flatMap を利用すると
n.flatMap(f)

// for式で書くと
for {
  a <- n
  b <- f(a)
} yield b
```

```hs:Haskell
f :: Int -> Maybe String
f = \x -> Just $ show x
n :: Maybe Int
n = Just 1

-- >>= を利用すると
n >>= f

-- do記法で書くと
do
  a <- n
  f a
```

# Further Reading

- [箱で考えるFunctor、ApplicativeそしてMonad - Qiita](http://qiita.com/suin/items/0255f0637921dcdfe83b)

HaskellのFunctor, Applicative, Monadについて箱のイメージで説明したブログ記事

> [Functors, Applicatives, And Monads In Pictures - adit.io](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html)

の翻訳です。
ここでいう「箱」が上述の型**C**に相当します。