Endo 是“合成下的内同态幺半群”。 appEndo 是该类型的字段。
newtype Endo a = Endo { appEndo :: a -> a }
-- i.e.
Endo :: (a -> a) -> Endo a
appEndo :: Endo a -> (a -> a)
您可以将“endomorphism”视为输入和输出类型相同的函数的技术正确术语 (a -> a)。
Endo 是 Monoid 的一个实例,其组成:
instance Monoid (Endo a) where
mempty = Endo id
Endo f `mappend` Endo g = Endo (f . g)
为了让规律更容易掌握,我们以List类型为例:
instance Foldable [a] where
foldMap f [] = mempty
foldMap f (x:xs) = f x `mappend` foldMap f xs
-- i.e.
-- foldMap f [a, b, …, w] == f a `mappend` f b `mappend` … `mappend` f w
当我们评估法律的 RHS 时:
foldMap (Endo . f) t
== foldMap (\x -> Endo (f x)) [a, b, …, w]
== (\x -> Endo (f x)) a `mappend` … `mappend` (\x -> Endo (f x)) w
== Endo (f a) `mappend` Endo (f b) `mappend` … `mappend` Endo (f w)
recall mappend for Endo 是作曲,所以上面是
== Endo (f a . f b . … . f w)
最后我们使用appEndo (…) z取出组合函数并将其应用到初始值z:
appEndo (Endo (f a . f b . … . f w)) z
== (f a . f b . … . f w) z
== f a (f b ( … (f w z) … ))
这正是foldr 对列表的定义。
foldl 类似,Dual 是另一个幺半群实例,Dual a `mappend` Dual b == Dual (b `mappend` a) 和getDual 取出内部幺半群。应该很容易看出这是如何产生foldl 的。
fold 函数将可折叠的幺半群折叠成单个幺半群。再次以List为例,fold可以实现为
fold [a, b, …, w] == a `mappend` b `mappend` … `mappend` w
可以从foldMap检索到:
foldMap id [a, b, …, w] == id a `mappend` id b `mappend` … `mappend` id w
== a `mappend` b `mappend` … `mappend` w
这显示了身份fold = foldMap id 的建议方式。