2012-01-19 87 views
3

我有这个功能懒洋洋地看一个日志文件,日志文件中的行...消费懒洋洋的(连续)批次

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

顺便提一下这个问题,懒惰IO这样有很多问题(主要涉及资源分配),一般应该避免。 – ehird

回答

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 [email protected](x:_) 
    | p x  = concatWhen p xxs 
    | otherwise = "" : concatWhen p xxs 
wrapConcatWhen _ _ = [] 

但是,看着它越近,你的concatWhen也应该是懒惰不够,或许有点低效率由于额外break分配了一些对构造函数,如果它没有被优化了。

什么是你有?

+0

实际上,是的,它只有一半的工作 - 它只是不会返回一个连接的组,直到与谓词不匹配的行,这是合理的。愚蠢的是,我只用匹配线进行测试。感谢让我再看一次!懒惰的评价是奇妙的:) –

相关问题