在作家monad中传递和倾听的重点是什么?

时间:2016-01-16 20:59:50

标签: haskell monads monad-transformers

我在书中learnyouahaskell一直在学习单子。 在阅读了作家monad之后,我决定查看Control.Monad.Writer.Class的文档。

在那里,我看到他们还实现了listenpass函数,但我无法理解它们的用途。有人可以给我一个很好的例子,这样我就能理解如何使用listenpass吗?

2 个答案:

答案 0 :(得分:8)

以下是定义Control.Monad.Trans.Writer.Strictlisten的{​​{1}}代码:

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) 是一个monad转换器,为其他monad提供WriterT功能,简单Writer类型定义为Writer,在type Writer w = WriterT w Identity monad中绑定函数(Identity<-)只是变量绑定,所以如果我们分解上面代码的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) 允许您访问Writer monad中Writer操作生成的日志,listen为您提供了一种方法来更改Writer monad中的日志。

假设您有一个pass,并且只有在它生成的日志满足某些条件时才想记录操作:

Writer [String]

答案 1 :(得分:3)

Writer内部,您无法检查已写入的内容,直到您使用execWriterrunWriter运行(或“解包”)monad。但是,您可以使用listen检查某些子操作写入编写器的内容,然后将值附加到编写器状态,并且可以使用pass来修改所写的内容。

考虑使用WriterT进行日志记录的应用程序示例:

import Control.Monad.Writer

-- Monad stack for the application uses IO, wrapped in a logging WriterT
type App a = WriterT [String] IO a

-- utility to write to the log
logMsg :: String -> App ()
logMsg msg = tell [msg]

-- gets an Int from user input (and logs what it does)
getInt :: App Int
getInt = do
    logMsg "getting data"
    n <- liftIO getLine
    logMsg $ "got line: " ++ show n
    return . read $ n

-- application logic that uses getInt and increments the result by 1
app :: App Int
app = do
    n <- getInt
    return $ n + 1

-- main code runs the application and prints the log
main = do
    (res, logs) <- runWriterT app
    print $ "Result = " ++ show res
    putStrLn "Log: "
    mapM_ putStrLn logs

现在,由于某种原因,在app内,我想知道getInt写入日志的消息。我可以用listen

来做到这一点
app :: App Int
app = do
    (n, logs) <- listen getInt
    let numLogLines = length logs
    logMsg $ "getInt logged " ++ show numLogLines ++ " lines"
    return $ n + 1