13.モノイド
モノイド圏は、集合の要素を射に、二項演算子を射の合成に、そして、単位元を恒等射にし、結合律、単位律が成り立っているものをいう。
例えば、整数の乗算の場合には、
1) 対象:シングルトン(通常星印で表される)
2) 射:整数
3) ドメイン、コドメイン:シングルトン
4) 恒等射:1
5) 合成: \(\times\)
① 結合律:満足
② 単位律:満足
しかし、上記の例でみたように射は集合の要素となるので、圏としては、余りにも細かいものが見えて気持ちよくない。そこで、構成要素を隠すように抽象化したい。しかし、いきなり、抽象化の議論を進めるのは気が引けるので、モノイドとは何かをHaskellを利用して慣れておこう。
13.1 Haskellでのモノイド
HaskellではモノイドはData.Monoidでクラスとして次のように定義されている。
class Monoid m where mempty :: m mappend :: m -> m -> m mconcat :: [m] -> m -- defining mconcat is optional, since it has the following default: mconcat = foldr mappend mempty
これに従えば、モノイドを使うときは\(mempty\)と\(mappend\)を定義する必要がある。なお、\(mappend\)は、中置関数\(<>\)でしばしば置き換えられる。
x <> y = mappend x y
また、結合律と単位律を満たさなけらばならないので、次の式を満たさなければならない。
-- Identity laws x <> mempty = x mempty <> x = x -- Associativity (x <> y) <> z = x <> (y <> z)
それでは、文字列の結合をモノイドとして定義しよう。次のようになる。
instance Monoid [a] where mempty = [] mappend x y = x ++ y mconcat = concat
積は次のようになる。積は数(\(Num\))に対する二項演算子であるが、モノイドとして定義するときは、\(Product\)と呼ばれる新しいデータ型(コンテナ)を用意する。
newtype Product n = Product n instance Num n => Monoid (Product n) where mempty = Product 1 mappend (Product x) (Product y) = Product (x * y)
和(余積)は次のようになる。ここでも、\(Sum\)と呼ばれる新しいデータ型(コンテナ)を用意する。
newtype Sum n = Sum n instance Num n => Monoid (Sum n) where mempty = Sum 0 mappend (Sum x) (Sum y) = Sum (x + y)
それでは利用してみよう。なお、Data.Monoidでは\(getProduct,getSum\)により、演算結果を数(\(Num\))のデータ型で表す関数を用意している。
Prelude> import Data.Monoid Prelude Data.Monoid> [1,2,3] <> [5,6] [1,2,3,5,6] Prelude Data.Monoid> [1,2,3] <> [] [1,2,3] Prelude Data.Monoid> [] <> [2,3,4] [2,3,4] Prelude Data.Monoid> Product 3 <> Product 5 Product {getProduct = 15} Prelude Data.Monoid> Product 3 <> Product 1 Product {getProduct = 3} Prelude Data.Monoid> Product 1 <> Product 2.34 Product {getProduct = 2.34} Prelude Data.Monoid> getProduct $ Product 32.5 <> Product 2.34 76.05 Prelude Data.Monoid> getProduct $ Product (3 / 4) <> Product ( 6 / 7) 0.6428571428571428 Prelude Data.Monoid> getSum $ Sum 4 <> Sum 5 9 Prelude Data.Monoid> getSum $ Sum 4 <> Sum 0 4 Prelude Data.Monoid> getSum $ Sum 0 <> Sum 5.5 5.5 Prelude Data.Monoid> getSum $ Sum ( 2.3 * 5) <> Sum (5.5 + 3.2) 20.2