fugafuga.write

日々のログ

すごいH本 part72

ファンクター則

Functor のインスタンスはファンクター則の2つの性質を満たす必要がある。 自前のファンクターを作る時はこの性質を満たす必要がある。

第1法則

idでファンクター値を写した場合、ファンクター値が変化してはいけない

idは引数をそのまま返すだけ(恒等写像)の関数。

Maybe が第一法則を満たしているか確認する。

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

fid に変えてみる

instance Functor Maybe where
    fmap id Nothing = Nothing
    fmap id (Just a) = Just (id a)

確認

*Main Lib> fmap id (Just 3)
Just 3
*Main Lib> id (Just 3)
Just 3
*Main Lib> fmap id [1..5]
[1,2,3,4,5]
*Main Lib> fmap id []
[]
*Main Lib> fmap id Nothing
Nothing

第2法則

すべてのファンクター値 x に対して fmap (f . g) x = fmap f (fmap g x) が成り立つ

2つの関数 f g において、

  • f と g の合成関数でファンクター値を写したもの
  • まず g, 次に f でファンクター値を写したもの

上記の2つが等しいことを要求する。

Maybe がこの法則を満たしているか確認する

1つめ

  1. fmap ((f . g) x) (Just x)
  2. Just ((f . g) x)
  3. Just (f (g x))

2つめ

  1. fmap f (fmap g (Just x))
  2. fmap f (Just (g x))
  3. Just (f (g x))

最終的に等しくなることが証明できる。

ファンクター則を破る

Functor のインスタンスなのにファンクター則を満たしていない例

data CMaybe a = CNothing | CJust Int a deriving (Show)

Maybe に似た型で、Just 部分のフィールドが2つある。1つ目のフィールドは Int で何らかのカウンタになる。

確認

*Main> CNothing
CNothing
*Main> CJust 0 "haha"
CJust 0 "haha"
*Main> :t CNothing
CNothing :: CMaybe a
*Main> :t CJust 0 "haha"
CJust 0 "haha" :: CMaybe [Char]
*Main> CJust 100 [1,2,3]
CJust 100 [1,2,3]

これを Functor のインスタンスにする

instance Functor CMaybe where
    fmap f CNothing = CNothing
    fmap f (CJust counter x) = CJust (counter + 1) (f x)

fmap するたびに counter が増えていく実装となっている。

*Main> fmap (++"ha") (CJust 0 "ho")
CJust 1 "hoha"
*Main> fmap (++"he") (fmap (++"ha") (CJust 0 "ho"))
CJust 2 "hohahe"
*Main> fmap (++"blah") CNothing
CNothing

ファンクター則を満たしているかどうか調べる

*Main> fmap id (CJust 0 "haha")
CJust 1 "haha"
*Main> id (CJust 0 "haha")
CJust 0 "haha"

id でファンクター値を写した結果と、単純に id をファンクター値に適用した結果が等しくないので CMaybe はファンクター則を満たしていない。

ファンクター則を満たしていると、その型の挙動についてある種の信頼がおけるようになる。

所感

ファンクター則を満たしていない状態でも実装できてしまうのはなんでなのか。 コンパイラがチェックしてもよさそうなのになーと思った。

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

  • 作者: MiranLipovaca
  • 出版社/メーカー: オーム社
  • 発売日: 2017/07/14
  • メディア: Kindle版
  • 購入: 4人 クリック: 9回
  • この商品を含むブログを見る