Monad Morphisms适用性问题

时间:2016-10-12 15:36:39

标签: haskell monads

我正在尝试做某事,我认为Monad态射是答案,但我不确定如何在这里正确应用它们。简而言之,我有以下设置:

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的帮助下能够做到的吗?怎么样?

1 个答案:

答案 0 :(得分:3)

如果你真正想要的是重用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的明显实施违反了这些法律中的第一条,因为mappendm >>= f中隐含的morph m >>= morph . f可以提供不同的结果,即使基础对布尔是一样的。