haskell - 在 Writer monad 中交换 `mappend`

标签 haskell monads monad-transformers writer-monad

摘要:在使用 Writer monad 时,我希望能够在 mappend 的 2 个不同版本之间切换,而不会丢失状态。

我使用两个 bool 标志来跟踪某些状态:

data Flags = F Bool Bool

现在我定义了两个 Monoid 实例,它们在 mappend 中组合标志的方式有所不同:

newtype XFlags = XF Flags

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

newtype SFlags = SF Flags

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

现在我可以有 2 个具有不同标志处理的 Writer monad:

type XInt = WriterT XFlags Identity Int
type SInt = WriterT SFlags Identity Int

现在我可以进行如下操作:

xplus :: XInt -> XInt -> XInt
xplus = liftM2 (+)

splus :: SInt -> SInt -> SInt
splus = liftM2 (+)

现在我想构建如下表达式:

foo = splus (return 1) (xplus (return 2) (return 3))

为此,我需要能够在两者之间进行转换,而不会丢失任何标志,并且最好不要解开 monad(使用 runWriter)。这部分我还没弄清楚。看起来有点像我可以尝试使用 monad 转换器嵌套 Writer,但我不确定它是否直接适用于此处。我将非常感谢有关实现此类操作的最佳方法的一些指导。

最佳答案

您可以使用 mapWriter 获得合理的东西.

sFromX :: XInt -> SInt
sFromX = mapWriter (\(x, XF fs) -> (x, SF fs))

现在你可以像这样编写foo

foo :: SInt
foo = splus (return 1) (sFromX (xplus (return 2) (return 3)))

您可能还需要相反的xFromS。如果您有两个以上不同的幺半群,也许值得更花哨并为标志容器编写一个类,例如:

class FlagContainer a where
  getFlags :: a -> Flags
  makeFromFlags :: Flags -> a

然后用它编写一个函数来替换 sFromXxFromS 和 您需要的任何其他内容。 (不过还没有测试过。)

关于haskell - 在 Writer monad 中交换 `mappend`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43485025/

相关文章:

oop - Haskell - 状态单子(monad)是命令式思维的标志吗?

haskell - 如何规避 Haskell 中的现有实例(失败)?

scala - 如何将 Future 的分离转换为分离的 Future

haskell - 如何在 Julia 中创建新类型?

haskell - ST Monad == 代码味道?

haskell - 对 'do' block 进行脱糖处理

haskell - Haskell 中的 Goto : Can anyone explain this seemingly insane effect of continuation monad usage?

haskell - [安全] 标记在 ghci 中是什么意思?

haskell - 如何使二叉树 zipper 成为Comonad的实例?

haskell - 定义访问多维数组的运算符