This question already has answers here:
How do `pass` and `listen` work in WriterT?
(4个答案)
5年前关闭。
我已经在learnyouahaskell一书中学习了有关monad的信息。
在阅读了有关作家monad的内容之后,我决定检查Control.Monad.Writer.Class的文档。
在那里,我看到它们还实现了
现在很明显,
假设您有一个
(4个答案)
5年前关闭。
我已经在learnyouahaskell一书中学习了有关monad的信息。
在阅读了有关作家monad的内容之后,我决定检查Control.Monad.Writer.Class的文档。
在那里,我看到它们还实现了
listen
和pass
函数,但我无法理解它们的用途。有人可以给我一个很好的例子,让我理解如何使用listen
和pass
吗? 最佳答案
这是来自Control.Monad.Trans.Writer.Strict
的代码,该代码定义了listen
和pass
:
listen :: (Monoid w, Monad m) => WriterT w m a -> WriterT w m (a, w)
listen m = WriterT $ do
(a, w) <- runWriterT m
return ((a, w), w)
pass :: (Monoid w, Monad m) => WriterT w m (a, w -> w) -> WriterT w m a
pass m = WriterT $ do
((a, f), w) <- runWriterT m
return (a, f w)
WriterT
是一个monad转换器,它为其他monad提供Writer
功能,简单的Writer
类型定义为type Writer w = WriterT w Identity
,在Identity
monad中,bind函数(<-
和>>=
)只是变量绑定(bind),因此如果我们分解上面代码的monadic部分:listen :: (Monoid w) => Writer w a -> Writer w (a, w)
listen m = Writer $
let (a, w) = runWriter m
in ((a, w), w)
pass :: (Monoid w) => Writer w (a, w -> w) -> Writer w a
pass m = Writer $
let ((a, f), w) = runWriter m
in (a, f w)
现在很明显,
listen
使您可以访问Writer monad内部的Writer操作生成的日志,pass
使您可以更改Writer monad内部的日志。假设您有一个
Writer [String]
,并且仅想在操作所产生的日志满足某些条件时才记录该操作:deleteOn :: (Monoid w) => (w -> Bool) -> Writer w a -> Writer w a
deleteOn p m = pass $ do
(a, w) <- listen m
if p w
then return (a, id)
else return (a, const mempty)
-- Or pass alone
deleteOn' :: (Monoid w) => (w -> Bool) -> Writer w a -> Writer w a
deleteOn' p m = pass $ do
a <- m
return (a, (\w -> if p w then mempty else w))
logTwo :: Writer [String] ()
logTwo = do
deleteOn ((> 5) . length . head) $ tell ["foo"]
deleteOn ((> 5) . length . head) $ tell ["foobar"]
{-
*Main> runWriter logTwo
((),["foo"])
-}
关于haskell - Writer monad的通过和收听的目的是什么? [复制],我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34832072/
10-12 21:01