我正在转换一些功能性的Haskell代码,该代码使用PARSEC使用Attoparsec,以期获得更好的性能。我已经进行了更改,所有内容都进行了编译,但是我的解析器无法正常工作。

我正在解析一个由各种记录类型组成的文件,每行。我的每个单独的函数用于解析记录或评论都可以正常工作,但是当我尝试编写一个函数以编译记录序列时,解析器总是会返回部分结果,因为它期望更多的输入。

这是我尝试过的两个主要变体。两者都有相同的问题。

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

对于第二个,我更改了记录/评论解析器以消耗终端字符。

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

我的方法有什么问题吗?还有其他方法可以实现我的尝试吗?

有帮助吗?

解决方案

我以前遇到过这个问题,我的理解是,这是由 <|> 在定义中起作用 sepBy:

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

这只会移至 pure [] 一次 (s *> scan) 失败了,这不会仅仅因为您处于输入的结尾。

我的解决方案只是打电话 feed 带着 empty bytestring Result 返回 parse. 。这可能是一种黑客,但似乎也是 attoparsec-iteratee 处理这个问题:

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

据我所知,这是唯一的原因 attoparsec-iteratee 在这里工作和普通的老 parse 不。

其他提示

如果您编写一个在失败之前消耗尽可能多的输入的Attoparsec解析器,则必须在达到输入结束时告诉部分结果。

您提供的信息很少,这就是为什么我认为很难为您提供良好帮助的原因。但是,我想发表一些评论:

  • 也许解析器没有意识到输入已经完成,并且取决于获得EOL或获得其他记录。因此,它要求部分结果。尝试将其喂食相当于EOL的希望。
  • 我不记得该代码,但是使用替代实例可能不利于解析性能。如果是这种情况,您可能需要在评论和记录类型上进行案件。
  • 我使用谷物进行大量二进制解析,这也非常快。虽然作为文本杰出者,Attoparsec似乎更好。您绝对应该考虑选项。
  • 另一种选择是从长远来看使用基于ITEMEREE的IO。约翰·拉托(John Lato)在最新的《 monad读者》(第16期)中撰写了一篇关于Iteratees的出色文章。终端条件是发信号的ITERETERES。当心iTerateE类型非常艰巨,并花一些时间习惯。
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top