【问题标题】:Why isn't Kleisli an instance of Monoid?为什么 Kleisli 不是 Monoid 的一个实例?
【发布时间】:2016-01-01 08:30:49
【问题描述】:

如果您希望附加两个类型为 (a -> m b) 的函数,以便只获得一个附加两个结果的相同类型的函数,您可以使用 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)

但是,目前Control.Arrow 中没有定义这样的实例。 通常,在 Haskell 中,我怀疑有一个很好的理由,但找不到哪一个。

注意

这个问题与this one 很相似。但是,对于 Monoid,我看不到定义实例的方法,例如:

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

因为已经有一个实例:

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

【问题讨论】:

    标签: haskell monads monoids kleisli


    【解决方案1】:

    在图书馆设计业务中,我们在这里面临一个选择点,我们选择在我们的集体政策中不完全一致(或缺乏一致)。

    Monad(或Applicative)类型构造函数的Monoid 实例可以通过多种方式实现。逐点提升总是可用的,但我们没有定义

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

    请注意,instance Monoid (a -&gt; b) 就是这样一种逐点提升,因此只要 m b 的幺半群实例对 b 上的幺半群进行逐点提升,(a -&gt; m b) 的逐点提升就会发生。

    我们一般不做逐点提升,不仅因为它会阻止其他 Monoid 实例的载体恰好是应用类型,而且因为 f 的结构通常被认为比x。一个关键的例子是 free 幺半群,更广为人知的是[x],它是由[](++) 组成的Monoid,而不是通过逐点提升。 monoidal 结构来自列表包装,而不是来自包装的元素。

    我首选的经验法则确实是优先考虑类型构造函数中固有的幺半群结构,而不是逐点提升或类型的特定实例化的幺半群结构,例如a -&gt; a 的组合幺半群。这些可以而且确实得到newtype 包装。

    关于Monoid (m x) 是否应该与MonadPlus m 一致存在的争论爆发了(同样与Alternative 一致)。我的感觉是,唯一好的 MonadPlus 实例是 Monoid 实例的副本,但其他实例不同。尽管如此,图书馆在这件事上并不一致,尤其是在(许多读者会看到我的这个老熊来了)这件事上……

    ...Maybe 的 monoid 实例,它忽略了我们通常使用 Maybe 来模拟可能的故障这一事实,而是观察到可以使用相同的数据类型思想来提供额外的元素一个半群如果它还没有一个中性元素。这两种结构产生了同构类型,但它们在概念上不是同源的。 (编辑更糟糕的是,这个想法实施起来很尴尬,给实例一个Monoid约束,而只需要一个Semigroup。我想看看Semigroup-extends-实现了 to-Monoid 的想法,但 没有 用于 Maybe。)

    回到Kleisli,我们有三个明显的候选实例:

    1. Monoid (Kleisli m a a)return 和 Kleisli 组合
    2. MonadPlus m =&gt; Monoid (Kleisli m a b) 提升mzeromplus 逐点超过-&gt;
    3. Monoid b =&gt; Monoid (Kleisli m a b)b 的幺半群结构提升到 m 然后 -&gt;

    我希望没有做出任何选择,只是因为不清楚该做出哪个选择。我不敢这么说,但我的投票是 2,优先考虑来自 Kleisli m a 的结构,而不是来自 b 的结构。

    【讨论】:

    • 你有“f的结构通常被认为比f的结构更重要。”这是一个错误吗?
    • 我也对你关于Maybe 的段落感到有些困惑。我认为 Maybe monoid 的问题在于它没有有一个 Semigroup a =&gt; Monoid (Maybe a) 约束,而是一个 Monoid a =&gt; Monoid (Maybe a) 约束,它忽略与一个半群的元素给出一个幺半群。
    • 感谢您发现错字。不,那不是Maybe bugbear。这只是增加伤害的侮辱。
    • 啊,我明白了。谢谢。而FWIW,它是由semigroups 包中的Option 实现的,这是一个围绕Maybe 的新型包装器。
    • @ReinHenrichs 您可以通过调用不同的事物来表示同构类型(例如,通过 newtype 实现)。这个名字是为了想法,为了一整串语义结构,类型本身只是其载体。通过使用实例推理来找到正确的语义管道,我们获得了如此多的省力省力,这与概念的命名有关。混淆概念是一种耻辱。当您想知道“前者将如何以不同方式表示”时,您会想念树木的树木。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-26
    • 2022-11-20
    • 1970-01-01
    • 2018-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多