Haskell 如何实现;“两个单体的乘积”;效果如何?

Haskell 如何实现;“两个单体的乘积”;效果如何?,haskell,monads,Haskell,Monads,假设我们有两个单子,m和m'。现在,假设我们有变量 -- in real problems, the restriction is some subclass MyMonad, so don't worry -- if it's the case here that mx and f must essentially be pure. mx :: Monad m'' => m'' a f :: Monad m'' => a -> m'' b 是否有一种方法可以创建类似于产品的

假设我们有两个单子,
m
m'
。现在,假设我们有变量

-- in real problems, the restriction is some subclass MyMonad, so don't worry
-- if it's the case here that mx and f must essentially be pure.
mx :: Monad m'' => m'' a
f :: Monad m'' => a -> m'' b
是否有一种方法可以创建类似于产品的东西
mxm'
?我知道这对于箭头是可能的,但对于单子来说似乎更复杂(不可能),特别是当试图编写
mx>>=f
应该做的事情时

要了解这一点,请定义

data ProdM a = ProdM (m a) (m' a)
instance Monad ProdM where
    return x = ProdM (return x) (return x)
但是现在,当我们定义
mx>=f
时,不清楚从
mx
传递到
f
的值是什么

    (ProdM mx mx') >>= f
        {- result 1 -} = mx >>= f
        {- result 2 -} = mx' >>= f

我希望
(mx>>=f)::ProdM
同构于
((mx>>=f)::m)x((mx>=f)::m')
是的,此类型是单子。关键是将两个结果都传递给
f
,并且只保留结果中的匹配字段。也就是说,我们从传递
mx
的结果中保留第一个元素,从传递
mx'
的结果中保留第二个元素。该实例如下所示:

instance (Monad m, Monad m') => Monad (ProdM m m') where
  return a = ProdM (return a) (return a)
  ProdM mx mx' >>= f = ProdM (mx >>= fstProd . f) (mx' >>= sndProd . f)
    where fstProd (ProdM my _) = my
          sndProd (ProdM _ my') = my'

ProdM
在软件包中以
Product

的名称提供。ehird的解决方案还意味着操作f运行两次。如果单子m和m'有明显的副作用,这可能是意外的。