我有这个功能懒惰地看日志文件......
follow :: Handle -> IO [String]
follow h = unsafeInterleaveIO $ do
catch (do line <- hGetLine h
lines <- follow h
return $ line : lines)
(const (do threadDelay (1000 * 100)
follow h))
...这很棒,因为它会返回一个无限列表,可以在追加日志文件时逐行处理,如下所示:
h <- openFile "test.log" ReadMode
ls <- follow h
mapM_ putStrLn ls
但是现在我需要在处理它们之前加入一些行。 (有些日志条目是xml拆分多行,我需要重新组合在一起)。我尝试了以下方法来做到这一点,但它永远不会终止,因为follow
永远不会,因为我理解它。
h <- openFile "test.log" ReadMode
ls <- follow h
mapM_ putStrLn (concatWhen (isPrefixOf "foo") ls)
concatWhen :: (String -> Bool) -> [String] -> [String]
concatWhen _ [] = []
concatWhen p as = let (xs, as') = span p as
(ys, rest) = break p as'
in (concat xs) : ys ++ (concatWhen p rest)
这样做有好办法吗?我是否需要在follow
内进行连接,或者是否有更优雅的方式可以对该函数返回的字符串数组进行操作?
如果它有任何区别,可以通过检查内容来确定一行是否是需要连接的组的最后一行。
答案 0 :(得分:3)
concatWhen p (x:xs)
| p x = let (ys,zs) = span p xs in concat (x:ys) : concatWhen zs
| otherwise = x : concatWhen p xs
concatWhen _ _ = []
应该够懒。但如果第一行不满足p
,它有不同的语义:(
所以你需要一个包装器
wrapConcatWhen p xxs@(x:_)
| p x = concatWhen p xxs
| otherwise = "" : concatWhen p xxs
wrapConcatWhen _ _ = []
但是,仔细观察它,你的concatWhen
也应该是懒惰的,由于额外的break
分配了一些对构造函数(如果它没有被优化),可能效率稍低。 / p>
你遇到的问题是什么?