Pseudo Engineer

ソフトウェアの話とか書いてくよ

Haskell道 その4

前回からかなり空いてますがHaskellの勉強はゆったりながら続けてますよ。

途中の章はいろいろ飛ばしてファンクターに行きましょう。

ファンクターとは?

ファンクターは文脈を持った箱です。箱の中にある値に文脈を持たせるともいえます。箱なので値を取り出して、加工して、また戻すこともできます。

ファンクターといえば、Maybe型が有名です。
Maybeの定義はこちら。

data Maybe a = Just a | Nothing

ここでの a は箱に入れる値の型です。Java的にはジェネリクス

Maybe型とは、値に不確実性の文脈を与えます。日本語的には「もしかすると〜かもしれない(失敗していなければ)」という意味です。

ファンクター値に関数を適用

ファンクターの箱の中にある値をファンクター値と呼んだりします。そしてファンクター値に関数に適用するのが fmap です。関数に適用させて得られた値はそのままファンクターに包まれたままです。イメージとしては、箱の中に入れたまま値を関数に適用させる感じです。

試しにMaybeのファンクター値に対して3を掛けてみます。

Prelude> let a = Just 2
Prelude> a
Just 2
Prelude> fmap (\x -> x * 3) a
Just 6

「2かもしれない」ものに対して3を掛ければ、「6かもしれない」ものになりました。ここで重要なのは文脈が維持されることにあります。

ファンクター則

第一法則「idで写してもファンクター値は同じである」

id は 与えられた引数をそのまま返す関数です。Maybeで示すと以下が成り立つ。

fmap id (Just 3) == id (Just 3)
第二法則「gの次にfでファンクター値を写したものと、合成関数f・gでファンクター値を写したものは同じである」

Maybeで示すと以下が成り立つ。

fmap f $ fmap g (Just 3) == fmap (f . g) (Just 3)

まとめると「箱から値を取り出して、与えられた関数を適用して、また戻す」という動作のみが fmap で実装されていればいいことになる。
与えられた関数を無視したり、関数適用以外の余計なことはしないということですね。