Monoid型クラス
単位元付きの二項演算がある
m -> m -> m
なので、無限に連結ができる
ex. 1 + 2 + 3 + ..
定義
hsclass Semigroup a => Monoid a where
mempty :: a
hsclass Monoid a where
mempty :: m
mappend :: m -> m -> m
mappend = (<>)
mconcat :: [m] -> m
mconcat = foldr mappend mempty
mconcat
は多くの場合、デフォルト実装で済む
例えば、 Monoid m
制約を必要とするような関数の定義の型を見ると
hsfoldMap :: (Monoid m, Foldable t) => (a -> m) -> t a -> m
こんな感じになる
多くの型クラスの場合は、 m a
のように、 *->*
なものとして扱われるが、Monoidの場合は *
として見られることになる
具体的に言うなら例えば
m
だけで Maybe Int
の意味を持つ
多くの場合は、 m
では Maybe
だが
これがどれだけ例外的なものなのかはよくわからんけど

雑な具体例
m -> m -> m
のパターンが肝なので
m==Int
のときなら *
とか +
とか max()
一方で ==
などは Int -> Int -> Bool
なので🙅♀️
m==String
のときなら、文字列連結 ++
とか
m==Bool
のときなら、論理演算である and
、 or
とか
List
((++), [])
Maybe
(<>, Nothing)
関数
(<>, \_ -> mempty)
具体例
*
を考える
hsnewtype Product a = Product { getProduct :: a } deriving (Eq, Ord, Read, Show, Bounded)
instance Num a => Monoid (Product a) where
mempty = Product 1
Product x `mappend` Product y = Product (x * y)
mempy
は 1
x * 1
は x
になる
mappend
は *
リスト考える
hsinstance Monoid [a] where
mempty = []
mappend = (++)
x ++ []
は x
になる
hs[1,2,3] `mappend` [4,5,6] -- [1,2,3,4,5,6]
[1,2,3] <> [4,5,6] -- [1,2,3,4,5,6]
mconcat [[1],[2,3],[4,5,6]] -- [1,2,3,4,5,6]
Booleanを考える
(演算子, 単位元)
の組を (||, False)
とするか、 (&&, True)
とするかの二通りが考えられる
前者を Any
、後者は All
と名付ける
hsnewtype Any = Any { getAny :: Bool } deriving (Eq, Ord, Read, Show, Bounded)
instance Monoid Any where
mempty = Any False
Any x `mappend` Any y = Any (x || y)
hsnewtype All = All { getAll :: Bool } deriving (Eq, Ord, Read, Show, Bounded)
instance Monoid All where
mempty = All True
All x `mappend` All y = All (x && y)
Ordering

p.272
Maybe a
を考える
Maybe型のモノイドの定義は複数考えられる
a
がモノイドである場合
hsinstance Monoid a => Monoid (Maybe a) where
mempty = Nothing
Nothing `mappend` m = m
m `mappend` Nothing = m
Just m1 `mappend` Just m2 = Just (m1 `mappend` m2)
a
がモノイドでない場合

p.276
参考
自分自身への関数 a -> a
を考える
引数と返り値の型が異なる関数はモノイドにならない
hsnewtype Endo a = Endo { appEndo :: a -> a }
instance Monoid (Endo a) where
mempty = Endo id
Endo f <> Endo g = Endo (f . g)
単位元が恒等関数 id
、演算子は関数合成 .
max/min関数のモノイド
IO
hsm1 <> m2 = do
x1 <- m1
x2 <- m2
return $ x1 <> x2
モノイドの畳み込み
Foldable型クラスについて
ref

p.277
tsinterface Monoid<A> extends Semigroup<A> {
readonly empty: A
}
参考
様々なモノイドの紹介、詳しい
モノイドの紹介。モノイドの各特徴の利点など
FizzBuzzの簡潔なコードを読み解く際にモノイドの解説がある(後半)
関数モノイド( Monoid (a -> b)
)を利用している
その中で3重のモノイドが使われている
monoidを的確に使った記事
hsのパフォーマンスの話