Text.ParserCombinators.ReadP中的最大咀嚼

时间:2014-03-16 13:01:00

标签: parsing haskell

Double的Read实例表现得非常简单:

reads "34.567e8 foo" :: [(Double, String)] = [(3.4567e9," foo")]

然而,Scientific的Read实例做了不同的事情:

reads "34.567e8 foo" :: [(Scientific, String)] = 
   [(34.0,".567e8 foo"),(34.567,"e8 foo"),(3.4567e9," foo")]

严格来说这是正确的,因为它提供了输入的可能解析列表。事实上,它同样可以在列表中包含(3.0,“4.567e8 foo”)以及其他一些。但是,像这样的情况(Double实例遵循)的通常行为是“maximal munch”,这意味着解析了最长的有效前缀。

我正在更新我的Decimal库,它有类似的行为,我想知道正确的事情在这里。 Scientific和Decimal都使用Text.ParserCombinators.ReadP,它旨在使编写Read实例变得容易,这似乎是ReadP解析器的一个特征。

所以我的问题:

1:在这些情况下,“读取”返回的正确方法是什么?我应该为Data.Scientific提交错误吗?

2:如果它只应该返回最大的munch(就像Double实例那样)那么你如何让ReadP这样做呢?

2 个答案:

答案 0 :(得分:1)

我已经决定最大的咀嚼是正确的事情。鉴于" 1.23"返回1的解析器是错误的。我自己被绊倒了,因为我曾经试过写一个" maybeRead"看起来像这样:

maybeRead :: (Read a) => String -> Maybe a
maybeRead str = case reads str of
   [v, ""] -> Just v
   _ => Nothing

这对Double来说很好,但是Decimal和Scientific失败了。 (显然可以修复它来处理多个返回结果,但我不希望这样做)。

问题原来是"可选"在Text.ParserCombinators.ReadP中。这使用对称选择运算符" +++",它返回带有和不带可选组件的解析。因此当我写了像

这样的东西
expPart <- optional "" $ do {...}

结果包括没有expPart的解析。

我写了一个不同版本的&#34;可选&#34;使用左偏选择运算符:

 myOpt d p = p <++ return d

如果解析器&#34; p&#34;使用任何文本,然后不使用默认值。如果你想要最大的咀嚼,这就是正确的事。

答案 1 :(得分:0)

对于#2,您可以更改科学包以使用根据旧语法定义的解析器:scientificPmaxmuch = scientificP <* eof :: ReadP Scientific

我认为#1的约定并不多:对于使用readText.Read.readMaybe的人来说,它没有什么区别。 readS_to_P reads :: ReadP Double可能比readS_to_P reads :: ReadP Scientific更快,但如果效率很重要,那么您可以将所有内容保留为ReadP直到结束。