2012-01-19 143 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

實際上,是的,它只有一半的工作 - 它只是不會返回一個連接的組,直到與謂詞不匹配的行,這是合理的。愚蠢的是,我只用匹配線進行測試。感謝讓我再看一次!懶惰的評價是奇妙的:) –

相關問題