懒惰消耗(连接)批次中的日志文件行

时间:2012-01-19 15:32:26

标签: haskell file-io lazy-evaluation

我有这个功能懒惰地看日志文件......

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内进行连接,或者是否有更优雅的方式可以对该函数返回的字符串数组进行操作?

如果它有任何区别,可以通过检查内容来确定一行是否是需要连接的组的最后一行。

1 个答案:

答案 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>

你遇到的问题是什么?