2010-06-07 29 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