如何使用 Monad.Writer 进行跟踪?
Posted
技术标签:
【中文标题】如何使用 Monad.Writer 进行跟踪?【英文标题】:How to use Monad.Writer for tracing? 【发布时间】:2016-10-02 17:07:32 【问题描述】:我的代码如下所示:
我想在 tokenize 函数中使用 tell 来写入同一个 Writer Monad。这可能吗?
tokenize :: T.Text -> T.Text -> [Token]
tokenize t token
| T.null t = addToken token []
| h == ' ' = addToken token (tokenize r "")
| h == '"' = let (t', r') = consumeString r
in addToken t' (tokenize r' "")
| otherwise = tokenize r (T.snoc token h)
where h = T.head t
r = T.tail t
parse :: [T.Text] -> W.Writer String [Token]
parse lines = do
let x = concatMap (\l -> tokenize l "") lines
W.tell "hello"
return x
main :: IO ()
main = do
content <- readContent
let lines = toTextList content
let (res, log) = W.runWriter $ parse lines
forM_ res $ \x ->
print x
print log
【问题讨论】:
一个选项可以是使用x <- concat <$> mapM (\l -> tokenize l "") lines
并以一元方式重写tokenize
。我对此不太满意,因为我们失去了concatMap
的出色流媒体性能。我想知道是否可以以某种方式制作 monadic 版本来保留流,知道我们在这里使用 writer monad...
@chi 我没有想到性能影响。将concatMapM
定义为折叠是否有帮助?
@user2297560 我不认为高效的concatMapM
在处理通用单子时可以存在。在作家的具体情况下......我不知道。
【参考方案1】:
您只需要将tokenize
的结果提升到Writer
:
tokenize :: T.Text -> T.Text -> W.Writer [Token]
tokenize t token
| T.null t = return $ addToken token []
| h == ' ' = return $ addToken token (tokenize r "")
| h == '"' = let (t', r') = consumeString r
in return $ addToken t' (tokenize r' "")
| otherwise = return $ tokenize r (T.snoc token h)
where h = T.head t
r = T.tail t
然后parse
必须更改以处理来自tokenize
的一元结果:
parse :: [T.Text] -> W.Writer String [Token]
parse lines = do
x <- concat <$> mapM (\l -> tokenize l "") lines
W.tell "hello"
return x
【讨论】:
以上是关于如何使用 Monad.Writer 进行跟踪?的主要内容,如果未能解决你的问题,请参考以下文章