微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

解析 – Text.ParserCombinators.ReadP中的最大咀嚼

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”使用任何文本,则不使用认值.如果你想要最大的咀嚼,这就是正确的事情.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐