Functorに触れてみよう

Haskellを書く上で、避けては通れない概念がいくつかあります。Functor(ファンクタ)もその１つですが、特徴的なものなので、理解しにくい人もいると思います。今回はできるだけコード例と図を示しながら解説していきます。後半ではFunctorを扱うライブラリのData.Functorについて見ていきます。

## 注意

・数学の圏論には詳しくないです。そのため、関手(数学のFunctor)についての話はできません。

・この記事で使用しているGHCのバージョンは8.8.3です。

## 最初のFunctor

はっきり言うと、Functorは型クラスです。`GHC.Base`で定義されていて、Preludeにも含まれています。定義はこうです。

```haskell
class Functor (f :: * -> *) where
  fmap :: (a -> b) -> f a -> f b
  (<$) :: a -> f b -> f a
  {-# MINIMAL fmap #-}
```

`MINIMAL fmap`とあるので、何かしらの型をFunctorのインスタンスにしたければ`fmap`のみを定義すればよい、とのことです。

`* -> *`がFunctorのキモです。型注釈に似ていますが、これはカインドについての注釈です。`Int`や`Char`、`Bool`のカインドは`*`つまり値そのものなのでFunctorのインスタンスにはなれません。GHCiで`:info`を使って型宣言を、`:kind`でカインドを見られます。見てみましょう。

```haskell
Prelude> :info Int
data Int = GHC.Types.I# GHC.Prim.Int#   -- Defined in ‘GHC.Types’
...
Prelude> :info Char
data Char = GHC.Types.C# GHC.Prim.Char#   -- Defined in ‘GHC.Types’
...
Prelude> :info Bool
data Bool = False | True  -- Defined in ‘GHC.Types’
...
Prelude> :kind Int
Int :: *
Prelude> :kind Char
Char :: *
Prelude> :kind Bool
Bool :: *
```

型宣言のあとにその型がどのインスタンスになっているかが表示されます。ここでは型宣言だけを見るためにそれらは省略しました。３つの型に共通するのは、どれも型コンストラクタが引数をとらないということ、すなわち値そのものということです。

ここで、Functorのインスタンスで私たちにも馴染み深いMaybeの型宣言を見てみましょう。

```haskell
data Maybe a = Nothing | Just a   -- Defined in ‘GHC.Maybe’
```

`Maybe a`というのは、`a`という型を引数にとるよ、という意味です。型コンストラクタが引数をとって、`Nothing`か`Just a`の型になるよ、と言っています。なんだか関数みたいですね。カインドも見てみましょう。

```haskell
Maybe :: * -> *
```

型引数を１つとって何かしらの値を「返す」型だということです。このカインドはFunctorのインスタンス`* -> *`に一致するので、Functorになれます。

Functorになるための`fmap`は、面白い型宣言をしています。

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

`fmap`は関数と、Functorに包まれた値を１つとって、関数を中の値に適用して再び包んだものを返します。図にするとこうです。

<img width="1616" alt="fmap.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486850/1e810139-67d3-a94b-a0ed-4147efa4ce77.png">

`fmap`は、その内部で下のように関数を適用しています。

<img width="1616" alt="inside-of-fmap.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486850/07c3b4fe-6fb7-3d74-7266-58da077d2068.png">

Maybeは`GHC.Base`でFunctorのインスタンスとして定義されています。

```haskell
instance  Functor Maybe  where
    fmap _ Nothing       = Nothing
    fmap f (Just a)      = Just (f a)
```

`fmap`でMaybeの値に関数を適用すると、Nothingなら取り出せる値がないのでNothingを、Justなら中の値に関数を適用してJustに包んで返す、ということがわかります。このとき、`fmap`の型注釈は次のようになると予想できます。

```haskell
fmap :: (a -> b) -> Maybe a -> Maybe b
```

さっそく使ってみましょう。

```haskell
Prelude> fmap (*3) (Just 8)
Just 24
Prelude> fmap (*3) Nothing
Nothing
```

`fmap`を使って、包まれた値に関数を適用できるというわけです。

## ファンクタ則

Functorのインスタンスになるためには、その動作がファンクタ則と呼ばれるルールを満たしていなければなりません。ルールは以下の2つです。

```haskell
fmap id = id
fmap (f . g) == fmap f . fmap g
```

つまり、仮にFunctorのインスタンス`SomeType`があるとき、次の2つの式は`True`にならなければならない、ということです。

```haskell
fmap id (SomeType x) == id (SomeType x)
fmap (f . g) (SomeType x) == (fmap f . fmap g) (SomeType x)
```

### その1

```haskell
fmap id = id
```

この法則は、`id`を`fmap`で中の値に適用したときに中の値が変わってはならない、というものです。

前提として、`id`は引数をそのまま返します。図にするとこうです。

<img width="972" alt="id.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486850/e31c8064-ff93-bfde-ab08-d7819f3188b5.png">

```haskell
id :: a -> a
```

`fmap id`の挙動は、こうなると予想できます。

<img width="1612" alt="fmap-id.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486850/0c20d797-b6ee-9e4a-aa0c-6cc198c09756.png">

```haskell
fmap id :: Functor f => f a -> f a
```

`Maybe`でこれを確認してみましょう。

```haskell
ghci> fmap id (Just 2)
Just 2
ghci> id (Just 2)
Just 2
ghci> fmap id Nothing
Nothing
ghci> id Nothing
Nothing
```

ちゃんと満たしていますね。

### その2

```haskell
fmap (f . g) == fmap f . fmap g
```

これは、関数合成を行った`f . g`を`fmap`するのは、`fmap g`に続けて`fmap f`をしたものと等しい、という意味です。

前提として、`f`と`g`は次のような関数とします。

<img width="1616" alt="compose.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486850/f93201f2-2a54-994e-dd34-f32deef7a16a.png">

``` haskell
f :: a -> b
g :: b -> c
f . g :: a -> c
```

`fmap f . g`は次のように動作するはずです。

<img width="1616" alt="fmap-f-g.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486850/3bb03626-8863-eaaf-5b8b-41b2dcff8b26.png">

```haskell
fmap f . g :: Functor f => f a -> f c
```

そして、`fmap f . fmap g`はこう動作するはずです。

<img width="1616" alt="fmap-f-fmap-g.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486850/5a8ed6aa-cf32-befd-30f0-b2afe7e73174.png">

```haskell
fmap f . fmap g :: Functor f => f a -> f c
```

`Maybe`を使って確認してみます。

```haskell
ghci> fmap ((+2) . (*3)) (Just 30)
Just 92
ghci> (fmap (+2) . fmap (*3)) (Just 30)
Just 92
ghci> fmap ((+2) . (*3)) Nothing
Nothing
ghci> (fmap (+2) . fmap (*3)) Nothing
Nothing
```

等しい値になっていることがわかります。

以上の2つから、`Maybe`はファンクタ則を満たしていることがわかりました。この後に紹介するFunctorたちもこの2つの法則を満たしています。

## その他のFunctorたち

Maybe以外にも、Functorとして定義されているものがいくつかあります。

### リスト

リストといってもFunctorになれるのは空リストです。リストは非決定性計算としても扱われるので、ある意味で値を包んだものと言えます。

```haskell
instance Functor [] where
    fmap = map
```

`fmap`は`map`であると定義されています。

`map`はリストの各要素に関数を適用するので、`fmap`に求められる動作としては間違っていません。`fmap`を`map`で書き直すとこうなります。

```haskell
instance Functor [] where
    map _ [] = []
    map f (x:xs) = f x : map xs
```

リストが空ならそのまま返し、そうでなければ関数を適用して返す、という動作です。もちろん、これはファンクタ則を満たしています。

```haskell
  fmap id [x1, x2, ..]
= [x1, x2, ..]
= id [x1, x2, ..]

  fmap (f . g) [x1, x2, ..]
= (f . g) [x1, x2, ..]
= fmap f (g [x1, x2, ..])
= (fmap f . fmap g) [x1, x2, ..]
```

```haskell
ghci> fmap id []
[]
ghci> fmap (*2) []
[]
ghci> (fmap (*2) . fmap (+10)) [1..10]
[22,24,26,28,30,32,34,36,38,40]
ghci> fmap ((*2) . (+10)) [1..10]
[22,24,26,28,30,32,34,36,38,40]
```

### タプル

GHCでは、2～4要素のタプルまでがFunctorのインスタンスとして定義されています。

```haskell
instance Functor ((,) a) where
    fmap f (x,y) = (x, f y)

instance Functor ((,,) a b) where
    fmap f (a, b, c) = (a, b, f c)

instance Functor ((,,,) a b c) where
    fmap f (a, b, c, d) = (a, b, c, f d)
```

どのファンクタも、最後の要素にのみ関数が適用されます。この実装は、ファンクタ則を満たしています。

```haskell
  fmap id (x, y)
= (x, id y)
= (x, y)
= id (x, y)

  fmap (f . g) (x, y)
= (x, (f . g) y)
= fmap f (x, g y)
= (fmap f . fmap g) (x, y)
```

もちろん、ペア以外のタプルでも同様です。

### Either

Eitherは2つの型引数をとり、LeftかRightで包んで返す型です。[^1]

```haskell
data Either a b = Left a | Right b
```

失敗する可能性のある計算を行う時に使い、Leftは失敗したときの値、Rightは成功したときの値です。ただ、`Either`のままだと型コンストラクタは`* -> * -> *`なので、Functorのインスタンスになれません。なので、`a`のみを部分適用して`* -> *`の形にします。

```haskell
instance Functor (Either a) where
    fmap _ (Left x) = Left x
    fmap f (Right y) = Right (f y)
```

ファンクタ則を満たしているという確認は一瞬です。型引数は`b`なので、`b`に関数が適用されるのがポイントです。

```haskell
  fmap id (Either a (b))
= Either a (id b)
= Either a b
= id (Either a b)

  fmap (f . g) (Either a (b))
= Either a ((f . g) b)
= fmap f (Either a (g b))
= (fmap f . fmap g) (Either a b)
```

### IO

IOは、I/Oアクションつまり動作とその結果を扱う型です。

```haskell
instance Functor IO where
   fmap f x = x >>= (pure . f)
```

この時、`fmap`は包まれた値に関数を適用するため、その型はこうなるはずです。

```haskell
fmap :: (a -> b) -> IO a -> IO b
```

注意してほしいのは、戻り値はIOに包まれているということです。

`>>=`と`pure`の型は次のようになります。

```haskell
(>>=) :: Monad m => m a -> (a -> m b) -> m b
pure :: Applicative f => a -> f a
```

`>>=`は動作の結果を取り出して関数に渡し、`pure`は文脈に合う値を生成します。これを踏まえると、`fmap`は`x`から値を取り出して`f`を適用し、`pure`で文脈に合う値(=`IO`)を返すことがわかります。

I/Oアクションの例としては、`getLine`や`putStrLn`があります。

```haskell
getLine :: IO String
putStrLn :: String -> IO ()
```

`getLine`はユーザからの入力を受け取り、IOで包んだ文字列として返します。`putStrLn`は文字列を受け取り、文字列を出力する**動作**を返します。

IOをFunctorにするメリットは、`IO`の殻をあまり意識せずにI/Oアクションから値を操作できることです。つまり、プログラムの純粋な部分とそうでない部分を分離できます。

サンプルとして、プログラムの引数を改行で区切って表示するプログラムを書いてみます。コマンドライン引数をとる関数として`getArgs`をインポートします。`unlines`を使って改行で引数をつなぎます。

```haskell
getArgs :: IO [String]
unlines :: [String] -> String
```

下がプログラムの本体です。

```haskell
import System.Environment (getArgs)
main = putStrLn =<< unlines <$> getArgs
```

`getArgs`で受け取ったコマンドライン引数のリストから値を取り出し、`unlines`を適用します。`<$>`は`fmap`の中置演算子バージョンです。それを先程の`=<<`で`putStrLn`に突っ込んで出力しています。

### 関数

関数、つまり`((->) r)`は、Functorの一種です。Functorは、包まれた値の世界`f a`での写像[^2]とも言えます。インスタンス実装の前に、`fmap`の型を考えてみます。`Functor f`の部分に`((->) r)`がくるので、下のようになると思われます。

```haskell
fmap :: (a -> b) -> (r -> a) -> (r -> b)
```

`fmap`が`(a -> b)`と`(r -> a)`をくっつけているように見えませんか?

```haskell
instance Functor ((->) r) where
    fmap = (.)
```

`((->) r)`は出力の欠けた関数なので、カインドは`* -> *`になります。もちろん、この実装はファンクタ則を満たします。

```haskell
  fmap id f
= f . id
= f
= id f

  fmap (g . h) f
= (g . h) . f
= fmap g (h . f)
= (fmap g . fmap h) f
```

関数のファンクタに`fmap`することは、関数合成をすることと等しいことがわかります。

## Functorのインスタンスを作ってみる

いくつかFunctorを見てきたので、そろそろFunctorのインスタンスを自作してみましょう。今回インスタンスにするのは次のような再帰的な型です。

```haskell
infixr 5 :::
data List a = None | List a ::: a
  deriving (Show)
```

目標は、`fmap`が`(a -> b) -> List a -> List b`になるように実装することです。早速やってみましょう。

```haskell
instance Functor List where
  fmap _ None = None
  fmap f (as ::: a) = fmap f as ::: f a

```

```haskell
ghci> fmap (*2) (None:::1:::2:::3:::4:::5)
 None ::: (2 ::: (4 ::: (6 ::: (8 ::: 10))))
ghci> fmap sum (None ::: [1..5]:::[1..10]:::[1..20])
None ::: (15 ::: (55 ::: 210 ))
```

ちゃんと動いています!!

## Data.Functor

続いては、Functorに関連する関数をまとめたData.Functorモジュールを見ていきます。次のような関数群があります。

```haskell
($>) :: Functor f => f a -> b -> f b
(<$>) :: Functor f => (a -> b) -> f a -> f b
(<&>) :: Functor f => f a -> (a -> b) -> f b
void :: Functor f => f a -> f ()
fmap :: Functor f => (a -> b) -> f a -> f b
(<$) :: Functor f => a -> f b -> f a
```

### fmap, (<$>), (<&>)

`fmap`はもうおなじみですね。`<$>`は`fmap`の中置演算子バージョンで、`<&>`はその引数を入れ替えたものです。`fmap`はインスタンスに依存しますが、`<$>`と`<&>`はData.Functorで実装されています。

```haskell
infixl 4 <$>

(<$>) :: Functor f => (a -> b) -> f a -> f b
(<$>) = fmap

infixl 1 <&>

(<&>) :: Functor f => f a -> (a -> b) -> f b
as <&> f = f <$> as
```

どちらの実装も、すんなり理解できると思います。`<$>`は`fmap`そのもの、`<&>`は関数と包まれた値を入れ替えたものですね。どちらも左結合で、`<&>`の優先順位は下から２番目で、`$`の１つ上なので、`<$>`より比較的後に評価されます。関数合成`.`は`infixr 9`ですから、関数を書き連ねたいときは`<&>`を、そうでなければ`<$>`を使うとよいかと思います。

### (<$), ($>)

```haskell
(<$) :: Functor f => a -> f b -> f a
($>) :: Functor f => f a -> b -> f b
```

`<$`は、右手のファンクタの値からファンクタのみを取り出して左手の値に被せる演算子です。`$>`はその逆です。

```haskell
infixr 4 <$
(<$)  :: a -> f b -> f a
(<$) =  fmap . const
infixr 4 $>
($>) :: Functor f => f a -> b -> f b
($>) = flip (<$)
```

```haskell
ghci> "abc" <$ Just 100
Just "abc"
ghci> "abc" <$ Nothing
Nothing
ghci> "abc" <$ Left 100
Left 100
ghci> "abc" <$ Right 100
Right "abc"
ghci> "abc" <$ [1..10]
["abc","abc","abc","abc","abc","abc","abc","abc","abc","abc"]
ghci> "abc" <$ (100,200)
(100,"abc")
ghci> Just "abc" <$ Just 100
Just (Just "abc")
```

### void

```haskell
void :: Functor f => f a -> f ()
```

`void`はファンクタの値をとり、ファンクタを`()`(ユニット)に被せて返します。

````haskell
ghci> void Just 100
Just ()
ghci> void Nothing
Nothing
ghci> void [1..10]
[(),(),(),(),(),(),(),(),(),()]
````

また、IOアクションの戻り値を捨てられます。

```haskell
ghci> mapM print "abc"
'a'
'b'
'c'
[(),(),()]
ghci> void $ mapM print "abc"
'a'
'b'
'c'
```

## まとめ

- Functorは何かしらの包まれた値を扱う型クラスです
- Functorのインスタンスはファンクタ則を満たします
- Haskellの「失敗を扱う型」や「状態を扱う型」(要するに値を包む型)はFunctorのインスタンスになっています

## 感想

個人的には、Functorはやっぱり包まれた値と相性がいいと思います。

## 参考文献

- [Data.Functor - Hackage](https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-Functor.html)

[^1]: Eitherについては[こちらの記事](https://qiita.com/Izawa_/items/ed0579a0e7d93e5c09cc)をどうぞ。

[^2]: 関数の別名で、入力が出力を定めているともいえるので、こう呼びます。