関数型プログラミング -Applicativeについて知る前に、Functorでできないことを知っておこう-

[前回の記事](https://qiita.com/masaki_shoji/items/0c1fbdbff6d37f7770ce)では、Functorについて軽く触れました。
今回はApplicativeについて言及する前に、Functorのfmapの定義だけでは実現ができない計算があることを見てみます。これを知ることで、Applicativeの有用性がより分かるようになると思います。
Applicativeについてはまた別の記事で書こうと思います。
言語は以前と同様Haskellを用います。

Applicativeに触れる前にFunctorについて、軽くおさらいしておきましょう。
Functorクラスは以下のようにfmapという関数が定義されているのでした。

# Functorのおさらい

## fmapについて
```haskell
class Functor f where
  fmap :: (a -> b) -> f a -> f b
```

これにより、「a型の値を引数にとりb型の値を返す関数」をファンクター値である「f a」に写し、ファンクター値「f b」を得ることができるのでした。

例を見てみます。

```haskell
-- 型が「Int -> Int」である関数fを定義する
Prelude> let f = (+1) :: Int -> Int
-- fmapにfを適用した結果得られる関数の型を表示
Prelude> :t fmap f
--「Functor f => f Int -> f Int」を型にもつ関数が得られる。ここでfはFunctorである
fmap f :: Functor f => f Int -> f Int
-- fmapを使用することにより、関数fをFunctor値である「Just 4 :: Maybe Int」に写すことができる。
Prelude> fmap f $ (Just 4 :: Maybe Int)
Just 5 -- Just
```

上記で使用した関数fは「Int型の値を引数にとり、Int型の値を返す**1引数の関数**」でした。

## fmapを多引数関数に適用することはできる？

ところで、多引数関数でファンクター値を写すことはできるのでしょうか。
はい、できます。

以下はカインドの話が絡むので、興味がない方はカインドのくだりは読み飛ばしても構いません。
カインドについて説明すると話が長くなってしまうので、これは別の機会で触れることにします。

ここで、改めてfmapの型を見てみましょう。

```haskell:fmapの型
fmap :: (a -> b) -> f a -> f b
```

「fmap :: (a -> b) -> f a -> f b」の型aおよび型bのカインドは「\*」です。
関数の型コンストラクタ(->)自体のカインドは「\* -> \* -> \*」ですが、
「Int -> Int」のように具体的な型の値が(->)に適用された結果の型のカインドは「\*」です。

ざっくり説明すると、「b = (x -> y)」（x, yのカインドは「\*」とする）
と置くと、「a -> b」は「(a -> (x -> y))」と置き換えられます。
ここで、型aのカインドは「\*」…①
また、x, yのカインドは「\*」であるから、具体的な型であるx, yを(->)に対して適用した「(x -> y)」の結果の型のカインドも「\*」…②
①、②より「a -> (x -> y)」の結果の型のカインドは「\*」。
したがって、多引数関数も適用することができると言うことになります。

### fmapに多引数関数を適用するとどうなる？

ここでは、fmapを用いて、多引数の関数 (\*)をMaybeのファンクター値に写した結果を見てみます。

```haskell
:t (*) --関数(*)の型は Num a => a -> a -> a。ここでaはNumクラスのインスタンス。
(*) :: Num a => a -> a -> a

-- 「Just 5」の「5」が(*)に部分適用され、その結果は(Just (5*))と同値となる。
Prelude> :t fmap (*) (Just 5)
fmap (*) (Just 5) :: Num a => Maybe (a -> a) -- Maybeの文脈に(a -> a)という「関数」が入っている

-- (Just (5*))の型を上記の結果と見比べてみる。
Prelude> :t (Just (5*))
(Just (5*)) :: Num a => Maybe (a -> a) --fmap (*) (Just 5)と同一の型
```

上記の結果得られた値の型は「Num a => Maybe (a -> a)」です。
この値は「(Just (5*)))」と同値です。

「(Just (5*)))」は、
　「関数(\*)に型a（aはNumクラスのインスタンス）の値「5」が部分適用された結果の関数「(\*) 5」がMaybeの箱（文脈）に入っている」
と解釈できます。

さて、関数(\*)の主たる目的は、「Numクラス制約をもつ同一の型同士の値の積」を得ることでしょう。
Maybeの箱に入っている「(Just (5*))」に対して、同じくMaybeの箱に入っている「Just 3」を適用し、「Just (5 * 3) = Just 15」のような計算をしたくなる場面はしばしば発生するでしょう。
以下のようにfmapを適用して、これを実現することはできるのでしょうか。

```haskell
fmap (Just (5*)) (Just 3)
```

結論から言うと、これはできません。
ghciで上記を実行した結果を見てみましょう。

```haskell
Prelude> fmap (Just (5*)) (Just 3)

<interactive>:37:7: error:
    • Couldn't match expected type ‘Integer -> b’
                  with actual type ‘Maybe (Integer -> Integer)’
    • Possible cause: ‘Just’ is applied to too many arguments
      In the first argument of ‘fmap’, namely ‘(Just (5 *))’
      In the expression: fmap (Just (5 *)) (Just 1)
      In an equation for ‘it’: it = fmap (Just (5 *)) (Just 1)
    • Relevant bindings include
        it :: Maybe b (bound at <interactive>:37:1)
```

fmapの型は「(a -> b) -> f a -> f b」です。
ここで、「(a -> b)」の型aと「f a」の型aは同一の型でなければなりません。
上記の例では、「(a -> b)」の部分に、「Integer -> b」の型の値が適用されなければなりませんが、「Maybe (Integer -> Integer)」型の値を適用しているためにエラーが起きています。

## まとめ
fmapにより、**多引数関数**をファンクター値に写したとき、

```haskell
fmap :: (a -> b) -> f a -> f b
```
の「f b」のbの部分には関数が入ります。
（例）Maybe (Int -> Int) 
※上記の例では、Maybeがfにあたり、(Int -> Int)がbにあたる。

**ファンクター値の中身の関数を、別のファンクター値に写そうとしたとき、fmapの定義ではその計算が実現ができません。**

では、どうすれば良いのでしょう。
これを解決するためには、以下の型定義をもつ関数が必要です。

```haskell
(欲しい関数) :: f (a -> b) -> f a -> f b
```

そして、まさしくこのような関数を定義しているのがApplicativeなのです。
Applicativeであれば、Functorでできなかった上記の計算ができるのです。
長くなってしまいましたので、続きはまた今度。