2016-11-19 60 views

回答

12

mempty对于某些应用肯定是需要的。例如,foldMapping的结果应该是空列表的结果?没有a的值可以提供映射函数来获得m。所以,需要有一个“默认”。这很好,如果这是一个关联操作的标识元素 - 例如它允许任意重新排序/分块折叠而不改变结果。当折叠一棵树时,实际上很多mempty可能出现在中间,但你总是知道它们会在最终结果中被“挤出”,所以你不依赖于可重现结果的确切树形布局。

这就是说,你的观点是正确的:Semigroup通常是足够的,如果在不需要mempty的地方使用这个类,它可能会更好(因为实际上有几个非常漂亮的类型,是Semigroup但不是Monoid)。然而,标准库的早期设计显然没有考虑到这个重要性足以保证额外的类,所以很多代码依赖于Monoid而不需要一个monoid。

所以 - 就像我们曾经有Monad同样的问题:大量的代码实际上只需要Applicative甚至只是Functor,但由于历史的原因被套牢Monad反正直到AMP。最终问题在于,Haskell类的层次结构实际上并不能真正地被精修,只是向下延伸,而不是向上。

+0

AMP似乎有点难过,因为AMP没有插入一些Kmett的类。一旦你开始讨论半群,你最终会发现自己想要'Apply','Alt','Bind','Semigroupoid','Foldable1'和'Traversable1'(我认为这些名字是正确的)。 – dfeuer

+0

@dfeuer在PureScript中有一点被搞糊涂了,它在库的设计中全面使用了'Semigroupoid'系列,我个人发现这些类实际上并不值得他们的重量。当你把东西砸在一起时,有一些东西可以粉碎它们是有用的! –

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 
4

这些天base功能类都SemigroupMonoid(和计划正在准备,使后者意味着前者) ,所以你不必在两个抽象之间进行选择 - 只要使用适合你的目的的最弱的假设。

这就是说,Monoid似乎是有些在日常实践比Semigroup更加有用。为什么是这样?我可以想到几个参数:

  1. 在编程中有用的东西,比如集合,往往有零或多个语义; MonoidSemigroup没有的方式自然地提取可组合的东西的集合。 (例如,[]中,免费Monoid,是一个集合的一个典型的例子。)
  2. 类型是Semigroup秒,但不Monoid小号往往当你开始撰写他们失去精度。给定两个非空列表xsys,我们知道xs <> ys至少有两个元素。但它的类型只承诺它至少有一个;有用的信息已被丢弃。
  3. 从社会的角度来看,人们对Cabal Hell非常害怕,以避免为了处理“非空洞的东西”而拉入额外的依赖关系。当您想要使用monads-sans- return和categories-sans-id时,安装semigroupoids软件包需要大量的“Kmett平台”。
+0

#2不清楚。这似乎意味着,如果'xs'和'ys'只是'Semigroup'值,那么我们会丢失如果它们是'Monoid'值就会保留的信息。 – chepner

+0

@chepner让我试着重述一下:我试图说当应用于某些类型(如非空列表)时,半群操作a - > a - > a'不准确。当使用它的类型恰好为0时,半群操作更有意义。追加列表以获得列表比追加非空列表来获取非空列表更自然 –