Monad Morphisms 适用性问题

Monad Morphisms applicability questiion

我正在尝试做一些事情,我认为 Monad Morphisms 是答案,但我不确定如何在此处正确应用它们。简而言之,我有以下设置:

import Control.Monad.Identity
import Control.Monad.Writer

data F = F Bool Bool

instance Monoid F where
    mempty =  F True False
    (F s0 c0) `mappend` (F s1 c1) = F (s0 && s1)
                                    (c0 || c1 || not (s0 || s1))
type S = Writer F
type SInt = S Int

上面我用两个布尔标志定义了数据类型 F,我使用 Writer monad 跟踪哪个状态。例如,我将在函数 foo:

中使用它们
foo :: SInt -> SInt -> SInt
foo = liftM2 (+)

现在,我想在某些情况下实现不同的标志处理逻辑,并在不更改 foo 的类型签名的情况下将其与 foo 一起使用。特别是,我想将上面的 Monoid 定义更改为:

instance Monoid F where
    mempty =  F True False
    (F s0 c0) `mappend` (F s1 c1) = F (s0 && s1) (c0 || c1)

这是我可以在 Monad Morphisms 的帮助下完成的事情吗?怎么样?

如果你真正想要的是重用foo,你可以让它多态...

foo :: (Monoid b) => Writer b Int -> Writer b Int -> Writer b Int

... 并将您的实例赋予两种不同的类型(我将围绕元组将它们写成 newtypes,但如果您愿意,您可以采用不同的方式):

newtype F = F { unF :: (Bool, Bool) }
    deriving (Eq, Show)

instance Monoid F where -- etc.

newtype G = G { unG :: (Bool, Bool) }
    deriving (Eq, Show)

instance Monoid G where -- etc.

至于使用monad态射,你当然可以写一个函数,比如...

bar :: Writer F a -> Writer G a
bar = writer . fmap (G . unF) . runWriter

... 这实际上只是交换了 Monoid 实例,正如您最初想要的那样。但是,您将无法使用 mmorph 机制,因为它实际上不是 monad 态射。引用 Control.Monad.Morph:

-- A monad morphism is a natural transformation:

 morph :: forall a . m a -> n a

-- ... that obeys the following two laws:

 morph (m >>= f)  = morph m >>= morph . f
 morph (return x) = return x

bar 的明显实现违反了这些定律中的第一个,因为 m >>= fmorph m >>= morph . f 中隐含的 mappend 可以给出不同的结果,即使底层布尔值对是相同的。