【问题标题】:Why is Haskell unable to read "7e7" but able to read "7a7"?为什么 Haskell 无法读取“7e7”但能够读取“7a7”?
【发布时间】:2014-03-27 13:28:42
【问题描述】:

尝试做:

Prelude> reads "7a7" :: [(Int, String)]
[(7,"a7")]

Prelude> reads "7e7" :: [(Int, String)]
[]

我测试了中间所有可能的字符。除了'e',它们都可以工作。似乎Haskell 试图用科学计数法解释数字,但它不能,因为我要的是Int

对我来说这似乎是一个错误。

【问题讨论】:

  • 我也认为这是一个错误。如果这是故意的,我至少会认为 reads 被破坏(很像 head 和其他可能引发错误的纯函数)。
  • 我不确定,但可以很容易地想象,7e7 是 7*10^7 的表示。因此只找到一个整数,没有找到字符串。
  • reads "7e7" :: [(Float, String)] 返回[(7.0e7,"")]。我认为这是一个错误,IntRead 实例不应处理 e 特别像 Float
  • 如我所料。所以……我应该举报吗?实际上,如果 Haskell 确实以科学计数法解释 7e7,为什么不简单地返回整数呢? 70000000 是有效的 Int
  • @romeovs 是的,你应该报告它并在我的回答中包含提供的信息。

标签: string haskell


【解决方案1】:

GHC 确实有问题。它对Numeric.readSigned 的实现使用以下内容:

read'' r = do
    (str,s) <- lex r
    (n,"")  <- readPos str
    return (n,s)

lex 调用将尝试解析任何词位,这意味着对于“7e7”它会产生[("7e7", "")],因为“7e7”是浮点文字的完整词位。然后它尝试从readPos 中获取完整的解析,在这种情况下,Numeric.readDec 是传入的参数,readDec 将正确地为字符串“7e7”产生[(7, "e7")]。与(n, "") 的模式匹配失败,并以[] 结束。

认为应该简单如下:

read'' = readPos

【讨论】:

  • ReadInt 实例是根据Numeric.readSigned Numeric.readDec 定义的。
【解决方案2】:

7e7 :: Fractional a =&gt; a 所以不能读作Int,但可以读作FloatDouble

ghci> :t 7e7
7e7 :: Fractional a => a

【讨论】:

  • 好吧,我明白为什么它应该被读作Int,但为了保持一致,它不应该被读作7,而"e7" 是剩余的(或what-c​​hu-ma-callit ),比如"7a7"
【解决方案3】:

您使用的是哪个版本的 GHC?

这是我设置的终端会话的(已编辑)输出:

GHCi, version 7.4.1: http://www.haskell.org/ghc/  :? for help
Prelude> reads "7a7" :: [(Int, String)]
[(7,"a7")]
Prelude> reads "7e7" :: [(Int, String)]
[(70000000,"")]
Prelude> 

这里在如何解释输入方面存在歧义。 通常我认为将“7e7”解释为 70000000 的 Int 是完全可以接受的。编译器应该如何知道在第一个数字之后拆分字符串?

【讨论】:

  • 我正在使用更新的版本:GHCi, version 7.6.3
  • 不,这个输出是错误的。 reads "7e7" :: [(Int, String)] 应该是 [(7, "e7)]。似乎 GHC 7.4.1 有一个不同的错误。
  • @R.MartinhoFernandes 感谢您的评论,这有助于改善(我希望)我的回答。我不确定输出是否“错误”,尽管这显然不是 OP 想要的。我已经编辑了我的答案以试图澄清我的意思。 OP 遇到了编译器需要的信息比给出的信息更多的情况。
  • Haskell Report 定义这个函数的方式意味着它应该有我描述的输出。这就是为什么我说这个输出是错误的。