Haskell 仅在monad transformer中更新外部monad
我有一个monad用于可能失败的计算,并执行一些日志记录:Haskell 仅在monad transformer中更新外部monad,haskell,monads,monad-transformers,Haskell,Monads,Monad Transformers,我有一个monad用于可能失败的计算,并执行一些日志记录: f1 :: WriterT [String] (Either String) a f2 :: Writer [String] b 我有一个不会失败的功能,但会进行一些日志记录: f1 :: WriterT [String] (Either String) a f2 :: Writer [String] b 使用f2中的日志更新f1中的writer monad并捕获f2计算的输出的最佳方法是什么?目前我正在这样做: f2resul
f1 :: WriterT [String] (Either String) a
f2 :: Writer [String] b
我有一个不会失败的功能,但会进行一些日志记录:
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)
f2result do{tell;return r}(runWriter f2)
我正在使用lift使用不同的计算更新内部单子,因此切换Writer和任一单子都不能解决问题。如果定义了
f2
,最简单的方法可能是重构f2
,从而定义它:
f2 :: Monad m => WriterT [String] m b
这应该不会太难,因为Writer w b
被定义为Writer w Identity b
,而Identity
单子不会给你任何东西
然后,只需执行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…
作为rampion答案的后续操作,您可以改为重构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
MonadWriter
的[String]
参数需要以下GHC pragma:
{-# LANGUAGE FlexibleContexts #-}
与往常一样,pragma放在模块的顶部
在评论中,rampion给出了在此设置中包装函数的版本:
wrap :: MonadWriter w m => Writer w b -> m b
wrap = uncurry (<<) . (return *** tell) . runWriter
where (<<) = flip (>>)
wrap::MonadWriter w m=>Writer w b->m b
wrap=uncurry(包装器变成wrap::MonadWriter w m=>Writer w b->mb;wrap=uncurry(好吧,让我加入相互敬佩协会,并说我很欣赏MonadWriter typeclass的泛化:)感谢danr和rampion的回复。我选择使用wrap方法。虽然我可以更改f2的类型,但该函数会出现在其他上下文中,因此我希望在编写其类型时不参考特定调用函数的需要。