仅在monad变换器中更新外部monad

时间:2012-03-14 13:48:35

标签: haskell monads monad-transformers

我有一个monad用于计算可能会失败并进行一些记录:

f1 :: WriterT [String] (Either String) a

我有一个不会失败的功能,但会做一些记录:

f2 :: Writer [String] b

使用f2中的日志更新f1中的writer monad的最佳方法是什么,并捕获f2计算的输出?目前我正在这样做:

f2result <- (\(r,l) -> do {tell l; return r}) (runWriter f2)

我使用lift用不同的计算来更新内部monad,因此切换Writer和Either monad都无法解决问题。

2 个答案:

答案 0 :(得分:4)

如果您定义了f2,那么最简单的方法可能是重构f2,以便如此定义:

 f2 :: Monad m => WriterT [String] m b

这不应该太难,因为Writer w b被定义为WriterT w Identity bIdentity monad不会给你任何东西。

然后你就可以通过f1 >> f2来链接它们。

如果您无法重新定义f2,则可以随时使用相应的签名定义自己的:

 f2' :: Monad m => WriterT [String] m b
 f2' = WriterT . return $ runWriter f2

如果你有一堆f2来包装,你可以随时定义一个函数来包装它们

 wrap :: Monad m => Writer w b -> WriterT w m b
 wrap = WriterT . return . runWriter

所以你可以做f1 >> wrap f2a >> wrap f2b >> wrap f2c ...

答案 1 :(得分:4)

作为对斜率回答的跟进,您可以改为重构f2 任何MonadWriter

f2 :: MonadWriter [String] m => m a

如果无法改变其定义,你可以 像rampion一样包装它:

f2' :: MonadWriter [String] m => m a
f2' = do let (a,w) = runWriter f2
         tell w
         return a

[String]的{​​{1}}参数需要此GHC编译指示:

MonadWriter

与往常一样,编译指示放在模块的顶部。

在评论中,rampion给出了在此设置中包装函数的版本:

{-# LANGUAGE FlexibleContexts #-}