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实例遵循的情况),通常的行为是“ maximum munch ”,这意味着将解析最长的有效前缀。
我正在更新具有类似行为的Decimal库,并且我想知道这里的正确方法是什么。Scientific和Decimal都使用Text.ParserCombinators.ReadP,其目的是使编写Read实例变得容易,这似乎是ReadP解析器的特征。
所以我的问题是:
1:在这些情况下返回“读物”的正确选择是什么?我应该为Data.Scientific提交错误吗?
2:如果只返回最大的munch(像Double实例一样),那么如何获得ReadP来做到这一点?
我认为最大的mu念是对的。给定“ 1.23”,返回1的解析器是错误的。我自己被这个绊倒了,因为我曾经试图写一个如下所示的“ maybeRead”:
maybeRead :: (Read a) => String -> Maybe a
maybeRead str = case reads str of
[v, ""] -> Just v
_ => Nothing
这对于Double效果很好,但对于十进制和科学效果却失败。(显然,它可以固定以处理多个返回结果,但是我没想到需要这样做)。
问题出在Text.ParserCombinators.ReadP中是“可选”的实现。这使用对称选择运算符“ +++”,该运算符返回带有或不带有可选组件的解析。因此,当我写类似
expPart <- optional "" $ do {...}
结果包括没有expPart的解析。
我使用左偏选择运算符编写了不同版本的“可选”:
myOpt d p = p <++ return d
如果解析器“ p”使用任何文本,则不使用默认值。如果您想最大程度地增加吃货,就可以这样做。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句