11
9

More than 5 years have passed since last update.

HaskellのIntと2つのモノイド

Posted at

HaskellにはMonoidという型クラスがあります
モノイドというのは結合則を満たす演算子と単位元が存在する集合のことで

  • 自然数と足し算
  • 自然数と掛け算
  • 文字列の結合

などここには書き表せられないほどたくさんのものがモノイドの性質を満たします。

class Monoid a where
    mempty :: a
    mappend :: a -> a -> a

    mconcat :: [a] -> a
    mconcat = foldr mappend mempty

ところで整数の足し算と掛け算もどちらもモノイドなのですがHaskellのIntはどのようなMonoid のインスタンスになっているでしょうか?
実はIntはそもそもMonoidのインスタンスになっていません
その代わり Data.Monoid では SumProduct という二つの型が newtype で宣言されていてそれらがMonoidのインスタンスとなっています。

newtype Sum a = Sum { getSum :: a }

instance Num a => Monoid (Sum a) where
    mempty = Sum 0
    (Sum x) `mappend` (Sum y) = Sum (x + y)


newtype Product a = Product { getProduct :: a }

instance Num a => Monoid (Product a) where
    mempty = Product 1
    (Product x) `mappend` (Product y) = Product (x * y)

こうすることで

>>> (Sum 5) `mappend` (Sum 5)
Sum 10

のように無事 Int (Num a)にもモノイドの性質を付与することが出来ました :hatching_chick:
でもちょっと待って下さい :exclamation:
使うたびにいちいち SumProduct で包まなきゃいけないのでしょうか?
実際はもちろんそうなのですがそれほど面倒なわけでもありません
例えばsumproductを再実装してみましょう

sum' = Num a => [a] -> a
sum' = getSum . mconcat . fmap Sum

product' = Num a => [a] -> a
product' = getProduct . mconcat . fmap Product

どうでしょうか
変換が必要なのは入り口と出口だけであることがわかると思います
とっても便利ですね :cat2:

11
9
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
9