我可以理解mappend和associativity要求的原因。但为什么我们需要身份元素呢?它的实用有用性是什么?或者,也许我错过了一些重要的东西,但没有定义它,整个逻辑将不起作用。谢谢!为什么在Haskell中偏爱monoids而不是半群?为什么我们需要mempty?
回答
mempty
对于某些应用肯定是需要的。例如,foldMap
ping的结果应该是空列表的结果?没有a
的值可以提供映射函数来获得m
。所以,需要有一个“默认”。这很好,如果这是一个关联操作的标识元素 - 例如它允许任意重新排序/分块折叠而不改变结果。当折叠一棵树时,实际上很多mempty
可能出现在中间,但你总是知道它们会在最终结果中被“挤出”,所以你不依赖于可重现结果的确切树形布局。
这就是说,你的观点是正确的:Semigroup
通常是足够的,如果在不需要mempty
的地方使用这个类,它可能会更好(因为实际上有几个非常漂亮的类型,是Semigroup
但不是Monoid
)。然而,标准库的早期设计显然没有考虑到这个重要性足以保证额外的类,所以很多代码依赖于Monoid
而不需要一个monoid。
所以 - 就像我们曾经有Monad
同样的问题:大量的代码实际上只需要Applicative
甚至只是Functor
,但由于历史的原因被套牢Monad
反正直到AMP。最终问题在于,Haskell类的层次结构实际上并不能真正地被精修,只是向下延伸,而不是向上。
与所有其他抽象一样:您可以随意操作的操作越多,可以抽象得越复杂的事物。关于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
这些天base
功能类都Semigroup
和Monoid
(和计划正在准备,使后者意味着前者) ,所以你不必在两个抽象之间进行选择 - 只要使用适合你的目的的最弱的假设。
这就是说,Monoid
似乎是有些在日常实践比Semigroup
更加有用。为什么是这样?我可以想到几个参数:
- 在编程中有用的东西,比如集合,往往有零或多个语义;
Monoid
以Semigroup
没有的方式自然地提取可组合的东西的集合。 (例如,[]
中,免费Monoid
,是一个集合的一个典型的例子。) - 类型是
Semigroup
秒,但不Monoid
小号往往当你开始撰写他们失去精度。给定两个非空列表xs
和ys
,我们知道xs <> ys
至少有两个元素。但它的类型只承诺它至少有一个;有用的信息已被丢弃。 - 从社会的角度来看,人们对Cabal Hell非常害怕,以避免为了处理“非空洞的东西”而拉入额外的依赖关系。当您想要使用monads-sans-
return
和categories-sans-id
时,安装semigroupoids
软件包需要大量的“Kmett平台”。
#2不清楚。这似乎意味着,如果'xs'和'ys'只是'Semigroup'值,那么我们会丢失如果它们是'Monoid'值就会保留的信息。 – chepner
@chepner让我试着重述一下:我试图说当应用于某些类型(如非空列表)时,半群操作a - > a - > a'不准确。当使用它的类型恰好为0时,半群操作更有意义。追加列表以获得列表比追加非空列表来获取非空列表更自然 –
- 1. 什么是仿函数,为什么我们需要它们?
- 2. 为什么我们需要抽象类而不是虚拟类?
- 3. 为什么我们需要在JavaScript
- 4. Windows上的Spark - 什么是winutils,为什么我们需要它?
- 5. 什么是OWASP?为什么我们需要这个?
- 6. 什么是伴侣对象,为什么我们需要它?
- 7. Maven快照究竟是什么,为什么我们需要它?
- 8. 什么是jquery noConflict,为什么我们需要这个?
- 9. 为什么我们需要一个半关闭的插座?
- 10. 装配需要什么?为什么我们使用它们?
- 11. 当pread接受偏移值时,为什么我们需要lseek?
- 12. 为什么我们需要fieldset标签?
- 13. 为什么我们需要RIA?
- 14. 为什么我们需要.htaccess的worpdress?
- 15. 为什么我们需要9补丁?
- 16. 我们为什么需要纤维
- 17. 为什么我们需要BeginGetResponse和BeginRead?
- 18. 为什么我们需要TensorFlow tf.Graph?
- 19. 为什么我们需要Bower和Nuget?
- 20. 为什么我们需要ng-click?
- 21. 为什么我们需要`ngDoCheck`
- 22. 为什么我们需要设置SONAR_RUNNER_OPTS?
- 23. 为什么我们需要Anaconda 2.7?
- 24. 为什么我们需要mktemp?
- 25. 为什么我们需要ClassMethods和InstanceMethods?
- 26. 为什么我们需要ioc容器
- 27. 为什么我们需要RBAC许可?
- 28. 为什么我们需要scalaz.stream迭代?
- 29. 为什么我们需要Buffer.isBuffer方法?
- 30. 为什么我们需要WCF
AMP似乎有点难过,因为AMP没有插入一些Kmett的类。一旦你开始讨论半群,你最终会发现自己想要'Apply','Alt','Bind','Semigroupoid','Foldable1'和'Traversable1'(我认为这些名字是正确的)。 – dfeuer
@dfeuer在PureScript中有一点被搞糊涂了,它在库的设计中全面使用了'Semigroupoid'系列,我个人发现这些类实际上并不值得他们的重量。当你把东西砸在一起时,有一些东西可以粉碎它们是有用的! –