如何将状态monad S -> (A, S)
与costate comonad (E->A, E)
结合在一起?
我尝试了两种明显的组合S -> ((E->A, E), S)
和(E->S->(A, S), E)
,但是无论哪种情况,我都不知道如何定义组合的操作(return
,extract
,...等等)。
最佳答案
如果同时指定了O
或I
(即具有O
方法),则将两个monad I
和extract
组合会产生一个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,但是我没有尝试过。