简体   繁体   English

为什么Kleisli不是Monoid的一个例子?

[英]Why isn't Kleisli an instance of Monoid?

If you wish to append two functions of type (a -> mb) so you get only one function of the same type appending both results, you could use Kleisli to do so: 如果你想附加两个类型为(a - > mb)的函数,这样你只能得到一个相同类型的函数来追加两个结果,你可以使用Kleisli来做到这一点:

instance (Monad m, Monoid b) => Monoid (Kleisli m a b) where
    mempty = Kleisli (\_ -> return mempty)
    mappend k1 k2 =
        Kleisli g
            where
                g x = do
                    r1 <- runKleisli k1 x
                    r2 <- runKleisli k2 x
                    return (r1 <> r2)

However, currently there is no such instance defined in Control.Arrow . 但是,目前Control.Arrow没有定义此类实例。 As often, in Haskell, I suspect there is a good reason, but cannot find which one. 通常,在Haskell,我怀疑有一个很好的理由,但找不到哪一个。

Note 注意

This question is rather similar to this one . 这个问题是相当类似, 这一个 However, with Monoid I don't see a way to define an instance such as: 但是,使用Monoid我没有看到定义实例的方法,例如:

instance (Monad m, Monoid b) => Monoid (a -> m b) where
    [...]

since there is already an instance: 因为已经存在一个实例:

instance Monoid b => Monoid (a -> b) where
    [...]

In the business of library design, we face a choice point here, and we have chosen to be less than entirely consistent in our collective policy (or lack of it). 在图书馆设计业务中,我们在这里面临一个选择点,我们选择在集体政策(或缺乏集体政策)中不完全一致。

Monoid instances for Monad (or Applicative ) type constructors can come about in a variety of ways. Monad (或Applicative )类型构造函数的Monoid实例可以以多种方式出现。 Pointwise lifting is always available, but we don't define 逐点提升始终可用,但我们没有定义

instance (Applicative f, Monoid x) => Monoid (f x) {- not really -} where
  mempty         = pure mempty
  mappend fa fb  = mappend <$> fa <*> fb

Note that the instance Monoid (a -> b) is just such a pointwise lifting, so the pointwise lifting for (a -> mb) does happen whenever the monoid instance for mb does pointwise lifting for the monoid on b . 请注意, instance Monoid (a -> b)就是这样一个逐点提升,因此只要mb的monoid实例为b上的monoid逐点提升,就会发生(a -> mb)逐点提升。

We don't do pointwise lifting in general, not only because it would prevent other Monoid instances whose carriers happen to be applied types, but also because the structure of the f is often considered more significant than that of the x . 我们一般不进行逐点提升,不仅因为它会阻止其载体碰巧应用类型的其他Monoid实例,而且因为f的结构通常被认为比x的结构更重要。 A key case in point is the free monoid, better known as [x] , which is a Monoid by [] and (++) , rather than by pointwise lifting. 一个关键的例子是自由幺半群,更好地称为[x] ,它是[](++)Monoid ,而不是逐点提升。 The monoidal structure comes from the list wrapping, not from the elements wrapped. 幺半群结构来自列表包装,而不是来自包装的元素。

My preferred rule of thumb is indeed to prioritise monoidal structure inherent in the type constructor over either pointwise lifting, or monoidal structure of specific instantiations of a type, like the composition monoid for a -> a . 我的首选经验法确实优先考虑类型构造函数中固有的幺半群结构优先于点式提升,或类型的特定实例的幺半群结构,如a -> a的组合monoid。 These can and do get newtype wrappings. 这些可以并且确实得到newtype包装。

Arguments break out over whether Monoid (mx) should coincide with MonadPlus m whenever both exist (and similarly with Alternative ). 关于Monoid (mx)是否应该与MonadPlus m同时存在(和Alternative同样)的争论突破。 My sense is that the only good MonadPlus instance is a copy of a Monoid instance, but others differ. 我的感觉是唯一好的MonadPlus实例是Monoid实例的副本,但其他实例不同。 Still, the library is not consistent in this matter, especially not in the matter of (many readers will have seen this old bugbear of mine coming)... 尽管如此,图书馆在这个问题上仍然不一致,特别是在这个问题上(很多读者都会看到我的这个古老的虫子来了)......

...the monoid instance for Maybe , which ignores the fact that we routinely use Maybe to model possible failure and instead observes that that the same data type idea of chucking in an extra element can be used to give a semigroup a neutral element if it didn't already have one. ... Maybe的monoid实例,它忽略了我们经常使用Maybe来模拟可能的失败的事实,而是观察到在一个额外的元素中使用相同的数据类型的想法可以用来给半群提供一个中性元素,如果它还没有。 The two constructions give rise to isomorphic types, but they are not conceptually cognate. 这两种结构产生了同构类型,但它们在概念上并不相同。 ( Edit To make matters worse, the idea is implemented awkwardly, giving instance a Monoid constraint, when only a Semigroup is needed. I'd like to see the Semigroup -extends-to- Monoid idea implemented, but not for Maybe .) 编辑更糟糕的是,这种想法是实现得很笨拙,给人实例Monoid约束,当只有一个Semigroup是必要的。我想看到的Semigroup -extends-TO- Monoid的想法实现的,而不是 Maybe 。)

Getting back to Kleisli in particular, we have three obvious candidate instances: 特别是回到Kleisli ,我们有三个明显的候选实例:

  1. Monoid (Kleisli maa) with return and Kleisli composition Monoid (Kleisli maa)带有return和Kleisli组成
  2. MonadPlus m => Monoid (Kleisli mab) lifting mzero and mplus pointwise over -> MonadPlus m => Monoid (Kleisli mab)提升mzeromplus逐点->
  3. Monoid b => Monoid (Kleisli mab) lifting the monoid structure of b over m then -> Monoid b => Monoid (Kleisli mab)升降的幺半结构bm然后->

I expect no choice has been made, just because it's not clear which choice to make. 我希望没有做出任何选择,只是因为不清楚做出哪个选择。 I hesitate to say so, but my vote would be for 2, prioritising the structure coming from Kleisli ma over the structure coming from b . 我犹豫不决,但我的投票将是2,优先考虑来自Kleisli ma的结构来自b的结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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