我可以理解mappend和关联性要求的原因。但为什么我们需要身份元素呢?它的实用性是什么?或者也许我错过了一些重要的事情,如果没有定义它,整个逻辑就不会起作用。谢谢!
答案 0 :(得分:13)
某些应用程序当然需要mempty
。例如,foldMap
ping对空列表的结果应该是什么?没有a
值可以提供映射函数来获取m
。所以,需要有一个“默认”。如果这是关联操作的标识元素,那就太好了 - 例如,它允许在不改变结果的情况下任意重新排序/分块。当折叠在树上时,实际上很多mempty
可能会出现在中间,但你总是知道它们会在最终结果中被“挤出”,所以你不依赖于确切的树形布局可重复的结果。
那就是说,你的问题是正确的:Semigroup
通常是足够的,如果在不需要mempty
的地方使用这个类可能会更好(因为有实际上是一些非常漂亮的类型Semigroup
但不是Monoid
)。然而,标准库的早期设计显然没有考虑到这一点非常重要,以保证额外的类,所以很多代码依赖于Monoid
而不需要一个幺半群。
所以 - 与我们之前使用的Monad
相同的问题很多:很多代码实际上只需要Applicative
甚至只需Functor
,但由于历史原因,我们遇到{Monad
1}}无论如何直到AMP。最终问题是Haskell类层次结构实际上不能真正精简,只能向下扩展,而不是向上扩展
答案 1 :(得分:5)
这些天base
为Semigroup
和Monoid
提供了类别(并且正在制定计划以使后者暗示前者),因此您无需在两者之间进行选择抽象 - 只使用适合您目的的最弱假设。
尽管如此,Monoid
似乎在日常实践中比Semigroup
更有用。为什么是这样?我可以想到几行论点:
Monoid
以Semigroup
没有的方式自然地抽象出可组合的事物集合。 (例如,[]
,免费 Monoid
,是集合的典型示例。)Semigroup
但不是Monoid
的类型往往会失去精确度。鉴于两个非空列表xs
和ys
,我们知道xs <> ys
至少有两个元素。但它的类型只承诺它至少有一个;有用的信息已被丢弃。return
和categories-sans - id
时,安装semigroupoids
包需要一大块“Kmett平台”。答案 2 :(得分:3)
它与所有其他抽象相同:您拥有的操作越多,您可以抽象的事情就越复杂。关于Monoid
具体来说,这里有一些最受欢迎的功能,Semigroup
仅适用于:
foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
fold :: (Foldable t, Monoid m) => t m -> m
mconcat :: Monoid a => [a] -> a