题
我正在转换一些功能性的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类型非常艰巨,并花一些时间习惯。
不隶属于 StackOverflow