関手、適応可能、モノイド、折り畳み可能!

Haskell 人気!らしいので、挑戦してみました。が、何だかよく分からないコンセプトが多くて困ります。ノート代わりにここに書いてみます。

まず Functor クラス。Functor の日本語は関手。意味不明です。が、詰まる所、Functor クラスのインスタンスは fmap (map の汎用版) 関数が利用できる!便利!ということみたいです。

map :: (a -> b) -> [a] -> [b]
fmap :: Functor f => (a -> b) -> f a -> f b

Maybe は Functor のインスタンスなので、例えば、fmap で (Num a) => Maybe a 型に足し算したりできます:

Prelude> fmap (+7) (Just 3)
Just 10

Prelude> fmap (+7) Nothing
Nothing

fmap を使わない場合:

Prelude> (\f (Just x) -> Just (f x)) (+7) (Just 3)
Just 10

Prelude> (\f (Just x) -> Just (f x)) (+7) Nothing
*** Exception: <interactive>:26:2-26: Non-exhaustive patterns in lambda

Functor バンザイ!

次に Applicative クラス。Applicative Functor と呼ぶらしいです。Functor の強化版といったところでしょうか。これを使えば Applicative 同士で演算できる!便利!ということみたいです。このクラスには <$> とか <*> という変な演算子が定義されてます。

(Num a) => Maybe a 型同士で足し算してみます:

Prelude> (+) <$> Just 7 <*> Just 3
Just 10

Prelude> (+) <$> Just 7 <*> Nothing
Nothing

Prelude> (+) <$> Nothing <*> Just 3
Nothing

Prelude> (+) <$> Nothing <*> Nothing
Nothing

<$> は fmap のことです:

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

<*> は何者なのか:

(<*>) :: Applicative f => f (a -> b) -> f a -> f b

fmap そっくりです。結局、上の例はこういうことです:

(+) <$> Just 7 <*> Just 3
Just (7+) <*> Just 3
Just 10

それから Monoid クラス。謎です。何かの集合があって、そこに1個だけ結合法則を満たす二項演算子を定義する、的な。mempty が単位元、mappend が演算、です。例えば、数の集合に足し算を定義した Sum という型があります:

Prelude> Sum 7 `mappend` Sum 3
Sum {getSum = 10}

Prelude> Sum 3 `mappend` mempty
Sum {getSum = 3}

掛け算を行う Product もあります。

最後に Foldable クラス。このクラスの foldMap を自作のコレクションに実装すると、foldr とかが使えるようになります。で、foldMap を実装する際にさっきの Monoid が出てきます。

組み込みのリストを真似した Hairetu 型があるとします(訓令式ローマ字に聊かこだわりがあるです):

import Data.Monoid
import qualified Data.Foldable as F

data Hairetu a = Karappo | a `Tugi` Hairetu a
  deriving (Eq, Show)

instance F.Foldable Hairetu where
  foldMap f Karappo = mempty
  foldMap f (x `Tugi` xs) = f x `mappend` F.foldMap f xs

Hairetu 型の値を用意して、foldr を適用してみます:

Prelude> let hairetu = (1 `Tugi`) . (2 `Tugi`) . (3 `Tugi`) $ Karappo
Prelude> F.foldr (+) 0 hairetu
6

すご〜い。木も試してみます。下のような Nibungi 型があるとします:

data Nibungi a = Hasikko | Husi a (Nibungi a) (Nibungi a)
  deriving (Eq, Show)
  
instance F.Foldable Nibungi where
  foldMap f Hasikko = mempty
  foldMap f (Husi x hidari migi) = F.foldMap f hidari `mappend`
                                   f x `mappend`
                                   F.foldMap f migi

ghci で遊びます:

Prelude> let ki = Husi 5 (Husi 3 (Husi 2 Hasikko Hasikko) Hasikko) (Husi 7 Hasikko (Husi 11 Hasikko Hasikko))
Prelude> F.foldr (+) 0 ki
28

便利なもんですね。

いやはや、これらのモジュール (Data.Functor, Control.Applicative, Data.Monoid, Data.Foldable) を使いこなすのは実に大変そう…。

(コウヅ)

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中