如何将状态monad S -> (A, S)与costate comonad (E->A, E)结合在一起?

我尝试了两种明显的组合S -> ((E->A, E), S)(E->S->(A, S), E),但是无论哪种情况,我都不知道如何定义组合的操作(returnextract,...等等)。

最佳答案

如果同时指定了OI(即具有O方法),则将两个monad Iextract组合会产生一个monad。每个对象都被指定。如果O和I`同时指定,那么您有两种不同的“自然”方式获得单子(monad),这大概是不等效的。

你有:

unit_O :: a -> O a
join_O :: O (O a) -> O a
unit_I :: a -> I a
join_I :: I (I a) -> I a

在这里,为了清楚起见,我添加了_O_I后缀;在实际的Haskell代码中,它们不会在那里,因为类型检查器可以自行解决。

您的目标是证明O (I O (I a)))是monad。假设O是并列的,即存在一个函数extract_O :: O a -> a

然后我们有:
unit :: a -> O (I a)
unit = unit_O . unit_I
join :: O (I (O (I a))) -> O (I a)

当然,问题在于实现join。我们遵循以下策略:
  • 外部fmap上的O
  • 使用extract_O获取内部O的骑乘
  • 使用join_I组合两个I monads

  • 这导致我们
    join = fmap_O $ join_I . fmap_I extract
    

    为了使这项工作有效,您还需要定义
    newtype MCompose O I a = MCompose O (I a)
    

    并将相应的类型构造函数和反构造函数添加到上述定义中。

    另一种选择是使用extract_I而不是extract_O。这个版本更简单:
    join = join_O . fmap_O extract_I
    

    这定义了一个新的monad。我假设您可以用相同的方式定义一个新的comonad,但是我没有尝试过。

    10-07 14:26