[英]Why prefer monoids over semigroups in Haskell? Why do we need mempty?
我可以理解 mappend 和关联性要求的原因。 但是为什么我们需要标识元素呢?它有什么实际用处呢? 或者也许我错过了一些重要的东西,如果没有定义它,整个逻辑将无法工作。 谢谢!
某些应用程序肯定需要mempty
。 例如, foldMap
ping空列表的结果应该是什么? 没有a
值可以提供给映射函数来获得m
。 因此,需要有一个“默认”。 如果这是关联操作的标识元素,那就太好了——例如,它允许在不改变结果的情况下任意重新排序/分块折叠。 当折叠一棵树时,实际上很多mempty
可能会出现在中间,但你总是知道它们会在最终结果中被“挤出”,所以你不依赖于精确的树布局来获得可重复的结果。
这就是说,你和你关心的问题: Semigroup
会经常是足够的,它可能会更好,如果该类被用于任何mempty
不需要(因为实际上有几个很漂亮的类型是Semigroup
,但不Monoid
)。 然而,标准库的早期设计显然没有考虑到这一点足以保证额外的类,所以很多代码开始依赖于Monoid
而实际上并不需要Monoid
。
所以 - 与我们过去使用Monad
遇到的问题大致相同:许多代码实际上只需要Applicative
甚至只需要Functor
,但由于历史原因,无论如何在 AMP 之前都被Monad
卡住了。 最终的问题是 Haskell 类层次结构在事后无法真正细化,只能向下扩展,而不是向上扩展。
这些天base
功能类两个Semigroup
和Monoid
(和计划正在准备,使后者意味着前者),所以您不必在两个抽象之间做出选择-只用适合你的目的最弱的假设。
也就是说, Monoid
在日常实践中似乎确实比Semigroup
更有用。 这是为什么? 我可以想到几行论证:
Monoid
以一种Semigroup
没有的方式自然地抽象出可组合的事物集合。 (例如, []
,免费的Monoid
,是集合的经典示例。)Semigroup
而不是Monoid
的类型往往会失去精度。 给定两个非空列表xs
和ys
,我们知道xs <> ys
至少有两个元素。 但它的类型只承诺它至少有一个; 有用的信息被丢弃了。return
和类别,sans- id
,安装semigroupoids
包需要“Kmett平台”的一大块。这与所有其他抽象一样:您可以使用的操作越多,您可以抽象的东西就越复杂。 特别是关于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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.