Monoid型クラス
単位元付きの二項演算がある
m -> m -> mなので、無限に連結ができる
ex. 1 + 2 + 3 + ..
定義
code:hs
class Semigroup a => Monoid a where
mempty :: a
code:hs
class Monoid a where
mempty :: m
mappend :: m -> m -> m
mappend = (<>)
mconcat = foldr mappend mempty
mconcatは多くの場合、デフォルト実装で済む
例えば、Monoid m制約を必要とするような関数の定義の型を見ると
code:hs
foldMap :: (Monoid m, Foldable t) => (a -> m) -> t a -> m
こんな感じになる
多くの型クラスの場合は、m aのように、*->*なものとして扱われるが、Monoidの場合は*として見られることになる
具体的に言うなら例えば
mだけでMaybe Intの意味を持つ
多くの場合は、mではMaybeだが
これがどれだけ例外的なものなのかはよくわからんけどmrsekut.icon
雑な具体例
m -> m -> mのパターンが肝なので
m==Intのときなら*とか+とかmax()
一方で==などはInt -> Int -> Boolなので🙅♀️
m==Stringのときなら、文字列連結++とか
m==Boolのときなら、論理演算であるand、orとか
List
((++), [])
Maybe
(<>, Nothing)
関数
(<>, \_ -> mempty)
具体例
*を考える
code:hs
newtype 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は*
リスト考える
code:hs
mempty = []
mappend = (++)
x ++ []はxになる
code:hs
mconcat 1],2,3,[4,5,6 -- 1,2,3,4,5,6 Booleanを考える
(演算子, 単位元)の組を(||, False)とするか、(&&, True)とするかの二通りが考えられる
前者をAny、後者はAllと名付ける
code:hs
newtype 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)
code:hs
newtype 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
すごいH本.icon p.272
Maybe aを考える
Maybe型のモノイドの定義は複数考えられる
aがモノイドである場合
code:hs
instance 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がモノイドでない場合
すごいH本.icon p.276
参考
自分自身への関数a -> aを考える
引数と返り値の型が異なる関数はモノイドにならない
code:hs
newtype 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
code:hs
m1 <> m2 = do
x1 <- m1
x2 <- m2
return $ x1 <> x2
モノイドの畳み込み
Foldable型クラスについて
ref すごいH本.icon p.277
code:ts
interface Monoid<A> extends Semigroup<A> {
readonly empty: A
}
参考
様々なモノイドの紹介、詳しい
モノイドの紹介。モノイドの各特徴の利点など
FizzBuzzの簡潔なコードを読み解く際にモノイドの解説がある(後半)
関数モノイド(Monoid (a -> b))を利用している
その中で3重のモノイドが使われている
monoidを的確に使った記事
hsのパフォーマンスの話