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 >>= f
和 morph m >>= morph . f
中隐含的 mappend
可以给出不同的结果,即使底层布尔值对是相同的。
我正在尝试做一些事情,我认为 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 >>= f
和 morph m >>= morph . f
中隐含的 mappend
可以给出不同的结果,即使底层布尔值对是相同的。