在Data.Monoid
的文档中,它声明应满足以下法律:
mappend mempty x = x
mappend x mempty = x
mappend x (mappend y z) = mappend (mappend x y) z
mconcat = foldr mappend mempty
我对这些的理解是前两个是同一性,第三个是相关性。
但是第四行的法律是什么?身份再次,但mconcat
?
答案 0 :(得分:12)
在数学上,幺半群的定义需要存在mempty
之类的东西,如mappend
,满足前三个定律:左右同一性和相关性。
已经在类中添加了mconcat
方法,以反映列表中的累积通常与幺半群相关的事实。第四个定律是mconcat
的可执行规范:实际上,这个法则是提供mconcat
默认实现的代码行。使mconcat
成为该类的成员意味着,每Monoid
个实例,您可以自由地为mconcat
提供更有效的实现,只要它与默认值一致即可。
我不清楚以这种方式重新实现mconcat
是一个特别大的胜利。我倾向于避免mconcat
赞成(令人困惑的名字)fold
。
答案 1 :(得分:3)
mconcat
的目的不是提供有关幺半群的更多信息;这是一个实现细节。它是一个便利功能,但可以比默认定义更有效地实现。当考虑无限列表时,“更有效”可能意味着“可能”。
考虑Product
幺半群。以下内容永远不会终止,使用mconcat
的默认定义:
mconcat (map Product [0..])
即使很明显任何包含0的整数列表都应该生成0.但是,如果你要将函数重新定义为
mconcat = foldr (\acc v -> if acc == Product 0 then Product 0 else mappend acc v) empty
然后,包含至少一个零的无限列表的乘积仍将终止。 (当然,无限值的非零值列表仍然永远不会终止,但对于包含“早期”零的大型列表,此mconcat
仍然更有效。)