Ленивое использование строк файла журнала в (сцепленных) пакетах - PullRequest
3 голосов
/ 19 января 2012

У меня есть эта функция для ленивого просмотра файла журнала ...

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 Ответ

3 голосов
/ 19 января 2012
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, который выделяет несколько парных конструкторов, если он не оптимизирован.

В чем ваша проблема?

...