在图书馆设计业务中,我们面临着一个选择点,我们选择在我们的集体政策上不完全一致(或缺乏集体政策)。
Monoid
的实例Monad
(or Applicative
) 类型构造函数可以通过多种方式出现。逐点提升始终可用,但我们没有定义
instance (Applicative f, Monoid x) => Monoid (f x) {- not really -} where
mempty = pure mempty
mappend fa fb = mappend <$> fa <*> fb
请注意,instance Monoid (a -> b)
就是这样的逐点提升,所以逐点提升(a -> m b)
每当幺半群实例发生时,就会发生m b
对幺半群进行逐点提升b
.
一般来说,我们不进行逐点提升,不仅因为它会阻止其他Monoid
其载体恰好是应用类型的实例,也因为其结构f
通常被认为比x
。一个关键的例子是free幺半群,更广为人知的名称是[x]
,这是一个Monoid
by []
and (++)
,而不是逐点提升。幺半群结构来自列表包装,而不是来自包装的元素。
我更喜欢的经验法则确实是优先考虑类型构造函数中固有的幺半群结构,而不是逐点提升或特定类型实例化的幺半群结构,例如组合幺半群a -> a
。这些可以而且确实得到newtype
包装纸。
关于是否Monoid (m x)
应与MonadPlus m
每当两者都存在时(并且类似地Alternative
)。我的感觉是唯一的好处MonadPlus
实例是一个副本Monoid
实例,但其他方面有所不同。尽管如此,图书馆在这件事上并不一致,尤其是在以下问题上(许多读者已经看到我的这个老麻烦了)......
...的幺半群实例Maybe
,它忽略了我们经常使用的事实Maybe
对可能的失败进行建模,并观察到,如果半群还没有中性元素,则可以使用插入额外元素的相同数据类型想法来为半群提供中性元素。这两种结构产生了同构类型,但它们在概念上并不同源。 (Edit更糟糕的是,这个想法的实施很笨拙,例如Monoid
约束,当只有一个Semigroup
是需要的。我想看看Semigroup
-延伸至-Monoid
想法实现了,但是not for Maybe
.)
回到Kleisli
特别是,我们有三个明显的候选实例:
-
Monoid (Kleisli m a a)
with return
和克莱斯利组成
-
MonadPlus m => Monoid (Kleisli m a b)
起重mzero
and mplus
逐点结束->
-
Monoid b => Monoid (Kleisli m a b)
提升幺半群结构b
over m
then ->
我预计不会做出任何选择,只是因为尚不清楚该做出哪个选择。我犹豫是否要这么说,但我的投票是 2,优先考虑来自的结构Kleisli m a
超过来自的结构b
.