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这样做呢?
解决方法
我已经决定最大的咀嚼是正确的事情.给定“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的解析.
我使用左偏置选择运算符编写了不同版本的“可选”:
myOpt d p = p <++ return d
如果解析器“p”使用任何文本,则不使用默认值.如果你想要最大的咀嚼,这就是正确的事情.