简体   繁体   English

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

[英]Why prefer monoids over semigroups in Haskell? Why do we need mempty?

I can understand the reason for mappend and associativity requirement for it.我可以理解 mappend 和关联性要求的原因。 But why do we need the identity element what is the pragmatic usefulness in it?但是为什么我们需要标识元素呢?它有什么实际用处呢? Or maybe I've missed something important and without definition of it in instances the whole logic won't work.或者也许我错过了一些重要的东西,如果没有定义它,整个逻辑将无法工作。 Thank you!谢谢!

The mempty certainly is needed for some applications.某些应用程序肯定需要mempty For instance, what should be the result of foldMap ping over an empty list?例如, foldMap ping空列表的结果应该是什么? There's no a value you could feed the mapped function to obtain an m .没有a值可以提供给映射函数来获得m So, there needs to be a “default”.因此,需要有一个“默认”。 It's nice if this is an identity element of an associative operation – for example it allows arbitrary reordering/chunking the fold without changing the result.如果这是关联操作的标识元素,那就太好了——例如,它允许在不改变结果的情况下任意重新排序/分块折叠。 When folding over a tree, actually a lot of mempty s may show up in the middle but you always know they will get “squeezed out” in the end result, so you don't depend on the exact tree layout for reproducable results.当折叠一棵树时,实际上很多mempty可能会出现在中间,但你总是知道它们会在最终结果中被“挤出”,所以你不依赖于精确的树布局来获得可重复的结果。

That said, you're right with your concern: Semigroup would quite often be sufficient, and it would probably be better if this class were used wherever mempty isn't needed (since there are actually a few quite nifty types that are Semigroup but not Monoid ).这就是说,你和你关心的问题: Semigroup会经常是足够的,它可能会更好,如果该类被用于任何mempty不需要(因为实际上有几个很漂亮的类型是Semigroup ,但不Monoid )。 However, the early design of the standard library apparently did not consider this important enough to warrant the extra class, so lots of code came to rely on Monoid without really needing a monoid.然而,标准库的早期设计显然没有考虑到这一点足以保证额外的类,所以很多代码开始依赖于Monoid而实际上并不需要Monoid

So – much the same issue as we used to have with Monad : lots of code really only needed Applicative or even just Functor , but for historical reasons was stuck with Monad anyway until the AMP.所以 - 与我们过去使用Monad遇到的问题大致相同:许多代码实际上只需要Applicative甚至只需要Functor ,但由于历史原因,无论如何在 AMP 之前都被Monad卡住了。 Ultimately the problem is that Haskell class hierarchies can't really be refined after the fact, only extended downwards , not upwards.最终的问题是 Haskell 类层次结构在事后无法真正细化,只能向下扩展,而不是向上扩展。

These days base features classes for both Semigroup and Monoid (and plans are afoot to make the latter imply the former), so you don't have to choose between the two abstractions - just use the weakest assumption suitable for your purpose.这些天base功能类两个SemigroupMonoid (和计划正在准备,使后者意味着前者),所以您不必在两个抽象之间做出选择-只用适合你的目的最弱的假设。

That said, Monoid does seem to be somewhat more useful in daily practice than Semigroup .也就是说, Monoid在日常实践中似乎确实比Semigroup更有用。 Why is this?这是为什么? I can think of a couple of lines of argument:我可以想到几行论证:

  1. Things that are useful in programming, such as collections, tend to have zero-or-many semantics;在编程中有用的东西,比如集合,往往具有零或多语义; Monoid naturally abstracts composable collections of things in a way that Semigroup doesn't. Monoid以一种Semigroup没有的方式自然地抽象出可组合的事物集合。 (For example, [] , the free Monoid , is a classic example of a collection.) (例如, []免费的Monoid ,是集合的经典示例。)
  2. Types that are Semigroup s but not Monoid s tend to lose precision when you start composing them.当您开始组合它们时,属于Semigroup而不是Monoid的类型往往会失去精度。 Given two non-empty lists xs and ys , we know that xs <> ys has at least two elements.给定两个非空列表xsys ,我们知道xs <> ys至少有两个元素。 But its type only promises that it has at least one;但它的类型只承诺它至少有一个; useful information has been discarded.有用的信息被丢弃了。
  3. From a social perspective, folks are scared enough of Cabal Hell to avoid pulling in extra dependencies just to deal with "non-empty things".从社会的角度来看,人们对阴谋集团的地狱已经足够害怕,以避免为了处理“非空的东西”而引入额外的依赖。 When you want to work with monads-sans- return and categories-sans- id , installing the semigroupoids package requires a chunk of the "Kmett Platform".当你想用的单子,sans-工作return和类别,sans- id ,安装semigroupoids包需要“Kmett平台”的一大块。

It's the same as with all the other abstractions: the more operations you have at your disposal, the more complex things you can abstract over.这与所有其他抽象一样:您可以使用的操作越多,您可以抽象的东西就越复杂。 Concerning Monoid specifically, here are a few most popular functions, which Semigroup is just not enough for:特别是关于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