存在一个在范畴M上自然的、非恒等单子态射M~>M吗?

7
已知类型为 a -> a 的自然变换必须是恒同函数。这来自于 Yoneda 引理,也可以直接导出。这个问题要求证明单子范畴中单子态射也具有相同的性质。
考虑单子之间 M ~> N 的单子态射(保持两边单子操作的自然变换 M a -> N a)。我们可以询问是否存在一个单子态射 e :: (Monad m) => m a -> m a,它在每个单子上都能够以相同的方式工作。换句话说,单子态射 e 必须在单子类型参数 m 上具有单子自然性。
单子自然律规定对于任何两个单子 M 和 N 之间的单子态射 f: M a -> N a,我们必须有 f . e = e . f,其中适当的类型参数。
问题是,我们能否证明任何这样的 e 必须是一个恒同函数,还是存在一个非恒同单子态射 e 的反例,定义如下:
  e :: (Monad m) => m a -> m a
  e ma = ...

一个失败的尝试定义e是:

 e ma = do
         _ <- ma
         x <- ma
         return x

另一次失败的尝试是

 e ma = do
         x <- ma
         _ <- ma
         return x

这两个尝试具有正确的类型签名,但未通过单子态映射定律。

似乎无法将Yoneda引理应用于此情况,因为没有单子态映射Unit ~> M,其中Unit是单位单子态。我也找不到任何直接证明。

1个回答

2

我认为你已经尝试过所有有趣的可能性。我们可能定义的任何Monad m => m a -> m a函数都不可避免地会像这样:

e :: forall m a. Monad m => m a -> m a
e u = u >>= k
    where
    k :: a -> m a
    k = _

特别地,如果k = returne = id。为了使e不是idk必须以非平凡的方式使用u(例如,k = const uk = flip fmap u . const分别对应于您的两个尝试)。在这种情况下,u效果将被复制,导致e在选择许多单子m时无法成为单子态射。既然如此,唯一完全多态的单子态射就是id
让我们更明确地阐述这个论点。
为了清楚起见,我将暂时切换到join/return/fmap表示法。我们想要实现:
e :: forall m a. Monad m => m a -> m a
e u = _

我们可以用什么来填充右侧?最明显的选择是u。单独使用,它意味着e = id,这看起来并不有趣。然而,由于我们还有joinreturnfmap,我们可以选择归纳推理,以u作为基本情况。假设我们有一些v :: m a,是用手头上的工具构建的。除了v本身之外,我们还有以下可能性:
  1. join (return v),它是v,因此没有告诉我们任何新信息;

  2. join (fmap return v),它也是v;以及

  3. join (fmap (\x -> fmap (f x) w) v),对于某些其他根据规则构建的w :: m a和一些f :: a -> a -> a。(将f的类型添加m层,如a -> a -> m a,并添加额外的join以删除它们将无法得出任何结论,因为我们随后必须显示这些层的来源,而事情最终会归结为其他情况。)

唯一有趣的情况是第三种情况。此时,我将采取捷径:
join (fmap (\x -> fmap (f x) w) v)
    = v >>= \x -> fmap (f x) w
    = f <$> v <*> w

因此,任何非u的右侧都可以用f <$> v <*> w的形式表示,其中vw可以是u,也可以是这种模式的进一步迭代,最终在叶子节点处达到u。然而,这种应用表达式有一个规范形式,通过使用applicative定律将所有(<*>)的使用重新关联到左边来获得,在这种情况下必须像这样...

c <$> u <*> ... <*> u

在这里,省略号代表零个或多个u,由<*>分隔,c是一个适当元数的a -> ... -> a -> a函数。由于a是完全多态的,根据参数化原理,c必须是某个像const一样选择其参数之一的函数。因此,任何这样的表达式都可以用(<*)(*>)来重写...

u *> ... <* u

在省略号处,代表有零个或多个u,由*><*分隔,右侧没有*>跟着<*

回到开头,所有非id候选实现必须像这样:

e u = u *> ... <* u

我们也希望e成为一个单子态射。因此,它也必须是一个适用态射。特别地:

-- (*>) = (>>) = \u v -> u >>= \_ -> v
e (u *> v) = e u *> e v

即:

(u *> v) *> ... <* (u >* v) = (u *> ... <* u) *> (v *> ... <* v)

我们现在有一个明确的反例路径。如果我们使用应用定律将两边转换为规范形式,我们仍然会在左侧得到交错的uv,并且在右侧所有u之后得到所有v。这意味着该属性不适用于像IOStateWriter这样的单子,无论e中有多少(*>)(<*),或者哪些值由任一侧的类似于const的函数选择。快速演示:
GHCi> e u = u *> u <* u  -- Canonical form: const const <$> u <*> u <*> u
GHCi> e (print 1 *> print 2)
1
2
1
2
1
2
GHCi> e (print 1) *> e (print 2)
1
1
1
2
2
2

我找不到足够严谨的证明。我们如何证明除非 e = id,否则 u 的效果将被 必然 复制?(我们还可以编写 e u = do _ <- u; _ <- u; _ <- u; u 并进一步结合 u-效果。)我们如何数学描述“单子值 p :: m a 具有从 u :: m a 复制的多个效果?” 然后,我们如何证明重复(三倍、等等) u-效果必然导致违反单子态射定律? - winitzki
@winitzki 我更明确地阐述了我的论点。在答案的原始修订版中,我肯定犯了一个错误,就是提到幂等性,因为我观察到的故障更多地与效果的可交换性有关。 - duplode
这很有趣。我需要再考虑一下。我们如何证明只有一种实现非平凡的 e u 的方式,即使用您描述的形式为 u *> ... <* u 的某些表达式?为什么我们不能找到其他聪明而复杂的 fmapreturnjoin 的组合,以便得到其他东西?同时考虑应用态射也是一个不错的选择。证明适用态射的类似属性可能比证明单子态射的类似属性更容易。(唯一适用自然的适用态射是恒等态射吗?) - winitzki
(1)虽然更加清晰的表述会更好(我还在考虑中),但我相信我的三种情况是穷尽了的。只有 join _ 可以导致非 id 的结果,而第三种情况是唯一不会导致 id 或无限回归的方式。(2)关于 Applicative:非正式地说,如果你的唯一 Kleisli 箭头是 return,那么你就没有使用 Monad 带来的额外能力,所以最好使用 Applicative。(3)是的,类似的属性也适用于 Applicative 映射。从规范形式开始的部分,它是自包含的,应该足以作为证明。 - duplode
如果我们有一个单子范畴态射,它是单子自然的,那么我们也会有一个适用函子范畴态射,它是适用自然的。我认为证明没有这样的适用函子范畴态射可能更容易些。 - winitzki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接