繁体   English   中英

为什么在 Haskell 中更喜欢幺半群而不是半群? 为什么我们需要 mempty?

[英]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功能类两个SemigroupMonoid (和计划正在准备,使后者意味着前者),所以您不必在两个抽象之间做出选择-只用适合你的目的最弱的假设。

也就是说, Monoid在日常实践中似乎确实比Semigroup更有用。 这是为什么? 我可以想到几行论证:

  1. 在编程中有用的东西,比如集合,往往具有零或多语义; Monoid以一种Semigroup没有的方式自然地抽象出可组合的事物集合。 (例如, []免费的Monoid ,是集合的经典示例。)
  2. 当您开始组合它们时,属于Semigroup而不是Monoid的类型往往会失去精度。 给定两个非空列表xsys ,我们知道xs <> ys至少有两个元素。 但它的类型只承诺它至少有一个; 有用的信息被丢弃了。
  3. 从社会的角度来看,人们对阴谋集团的地狱已经足够害怕,以避免为了处理“非空的东西”而引入额外的依赖。 当你想用的单子,sans-工作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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM