在这个对“单子可以是共单子吗?”的回答中 我们看到
什么是双重的?是否有一类函子可以自动使自由单子成为共单子?
是的,您可以对构造进行二元化,但结果类的唯一成员是空函子,它的自由单子(恒等单子)确实也是一个共单子。不是很令人兴奋。
您所指的构造实际上几乎不需要经过,所以让我们放弃 Hask 的包袱,并按照以下一般性工作。让
(C, ⊗, 1) 是幺半群
F : C -> C 一个幺半群值函子,即有映射 1 -> FX 和 FX ⊗ FX -> FX 在 X 中是自然的,并且是单位的和结合的
定义 TX = X ⊗ F(TX)。假设这个递归定义在某种程度上是有意义的,我们可以在 T 上进行递归定义。然后我们可以将 T 变成具有以下结构映射的 monad:
单位由
X = X ⊗ 1
-> X ⊗ F(TX) [unit map of F]
= TX
加入由
T(TX) = TX ⊗ F(TTX)
= X ⊗ F(TX) ⊗ F(TTX)
-> X ⊗ F(TX) ⊗ F(TX) [join recursively under F]
-> X ⊗ F(TX) [multiplication of F]
= TX
当 ⊗ 是笛卡尔积时,此构造是您所指的 Alternative 函子上的自由共单子上的单子结构。事实上,Alternative 结构的 Applicative 部分是无关紧要的。只需要 Alternative 本身的类方法(加上 Functor):一个幺半群值仿函数。元素方面,构成上述连接的步骤由下式给出
(x :< xs) :< xss -> (x :< xs, xss)
-> (x, xs, xss)
-> (x, xs, fmap join xss)
-> (x, xs <|> fmap join xss)
-> x :< (xs <|> fmap join xss)
这很容易看出(通过设置k = id
)同意
(a :< m) >>= k = case k a of
b :< n -> b :< (n <|> fmap (>>= k) m)
由于我们的初始结构非常小,因此很容易对偶。所以让 (C, ⊗, 1) 继续是一个幺半群但现在假设
然后我们可以定义 UX = X ⊗ G(UX) (再次假设这在某种程度上是有道理的)并通过对偶结构为 U 配备一个共胞的结构。从某种意义上说,这是这里的真正答案,但为了解决您的具体问题,我们应该考虑一些具体选择 ⊗ 会发生什么。
首先假设⊗又是笛卡尔积。然后每个函子 G 都以独特的方式进行共模值(联合性迫使 GX -> GX x GX 成为对角线)。所以对于任何函子 G,我们得到一个共单子 UX = X x G(UX)。事实上,这只是函子构造上通常的 cofree 共单胞(证明你的口号中的“cofree comonad”部分是正确的;当 F 是幺半群值时,我们可以设置 G = F 并且 G 自动是共模态,然后 T和 U 具有相同的底层函子)。
对偶,如果 ⊗ 是 ⨿ 的余积,那么任何对 ⨿ 具有共模值的 G 也以独特的方式对 ⨿ 具有幺半值,所以 UX = X ⨿ G(UX) 也是 G 上的自由单子,并且是共生。
但是在 Hask 中,⨿ 的单位对象是空类型 0,并且 G 的单位应该具有类型 GX -> 0,这只有当所有 X 的 GX = 0 时才有可能(这在任何笛卡尔封闭类别中都是正确的) . 因此,在 Hask 中没有这种构造的有趣示例。这种缺乏对称性是类似于 Set 的范畴的典型现象。