2010-06-07 17 views
7

我正在轉換一些正在運行的Haskell代碼,它使用Parsec來代替使用Attoparsec來獲得更好的性能。我做了更改並編譯了所有內容,但解析器無法正常工作。使用Attoparsec時輸入不完整的問題

我正在解析一個由不同記錄類型組成的文件,每行一個。我的每個解析記錄或註釋的函數都能正常工作,但是當我嘗試編寫函數來編譯一系列記錄時,解析器總是返回一個部分結果,因爲它需要更多的輸入。

這些是我嘗試過的兩個主要變化形式。兩者都有同樣的問題。

items :: Parser [Item] 
items = sepBy (comment <|> recordType1 <|> recordType2) endOfLine 

對於第二個,我更改了記錄/註釋解析器以消耗行尾字符。

items :: Parser [Item] 
items = manyTill (comment <|> recordType1 <|> recordType2) endOfInput 

我的方法有什麼問題嗎?有沒有其他方法可以實現我所嘗試的?

回答

2

我碰到以前這個問題,我的理解是,它是由<|>作品的sepBy定義的方式造成:

sepBy1 :: Alternative f => f a -> f s -> f [a] 
sepBy1 p s = scan 
    where scan = liftA2 (:) p ((s *> scan) <|> pure []) 

這隻會轉移到pure []一旦(s *> scan)失敗,這不會僅僅因爲你處於輸入的結尾而發生。

我的解決方案只需致電feedempty ByteString Resultparse返回。這可能是怎樣的一個黑客,但它也似乎是如何attoparsec-iteratee涉及的問題:

f k (EOF Nothing) = finalChunk $ feed (k S.empty) S.empty 

至於我可以告訴大家這是在這裏attoparsec-iteratee作品和普通的老parse的確不是唯一的原因。

+0

謝謝,這解決了我的問題。 – 2010-06-07 14:56:36

0

你給的信息很少,這就是爲什麼我覺得很難給你很好的幫助。然而,我想給幾個意見:

  • 也許解析器沒有意識到輸入完成,它取決於獲取EOL或獲取另一條記錄。因此它要求部分結果。試着餵它相當於EOL,希望它能夠強制它。
  • 我不記得代碼,但使用Alternative實例可能對解析性能不利。如果是這種情況,你可能想要評論和recordTypes。
  • 我使用穀物進行大量的二進制解析,而且速度也非常快。儘管attoparsec看起來好於文本解析器。你一定要考慮這個選項。
  • 另一種選擇是在較長時間內使用基於迭代器的IO。約翰拉託在最新的monad讀者中做了一篇關於迭代的優秀文章(我相信問題#16)。行結束條件是要發信號的迭代。請注意,迭代類型非常艱鉅,需要一些時間來適應。
+0

感謝您的建議。我試圖將解析器簡化爲展示問題的最小版本,例如移除替代方案並僅創建一系列評論。在GHCi中,評論功能按我期望的那樣工作,但是項目功能是有問題的。我想知道我的方法是否存在根本性錯誤。我很高興分享任何可能有用的額外信息。我試着餵它一個額外的EOL,但它沒有任何區別。我在幾個地方看到了iteratees,但我之前沒有遇到它們,所以我現在想避免它們。 – 2010-06-07 13:46:16

5

如果您編寫的attoparsec解析器在失敗前消耗盡可能多的輸入,則必須在達到輸入結束時告訴部分結果延續。

+5

所以'喂'實際上是處理這種情況的正確方法?在文檔中更清楚一點可能是一個好主意 - 我知道當我第一次遇到它時,它讓我感到困惑。 – 2010-06-07 22:56:08