在Haskell中可疑的'Int'与'Integer'处理?

ntd*_*def 2 haskell types integer

只是为了踢,我想看看如果我在Haskell中定义一个函数会发生什么Int -> Int,知道它会溢出并且必须返回一个Integer.考虑以下:

factorial :: Int -> Int
factorial n = product [1..n]
Run Code Online (Sandbox Code Playgroud)

现在我知道如果我跑factorial 50,我会得到一个在'codomain'之外的数字factorial.由于Haskell是如此强类型,我希望它会返回一个错误.相反,GHCi返回一个奇怪的负面Int:

ghci> factorial 50
-3258495067890909184
Run Code Online (Sandbox Code Playgroud)

请注意

ghci> maxBound :: Int
9223372036854775808
Run Code Online (Sandbox Code Playgroud)

因为我在64位上运行.

我发现这种行为有点可怕:为什么Haskell没有引发错误?为什么factorial 50返回一个随机的负数?任何澄清将不胜感激.

ami*_*dfv 19

Int类型定义为"至少具有[-2 ^ 29 ... 2 ^ 29-1]范围的固定精度整数类型." [0]范围因机器而异,但您可以使用minBound和找到它maxBound

它溢出的原因是它为它分配了固定数量的内存.想象一个更简单的例子 - 内存中的正整数,其最大值为7(在内存中存储为3位)

0表示为000,二进制
1表示为001
2表示为010等.

注意位数学是如何工作的:当你加1时,你要么把最小的数字从0变为1,要么把它从1变为0,并对下一个最重要的数字做同样的操作.

例如,011 + 1100.

现在,如果你没有(就像Haskell所做的那样)在没有下一个最重要的数字的情况下执行此操作,那么它只会像往常一样增加,但是"会被切断".例如,111 + 1000不是1000.这就是Haskell所发生的事情,除此之外其最低值(表示为一系列0s)是其最低负数.它使用其"最左边"位来表示+/-.你需要做到(maxBound :: Int) + (maxBound :: Int) + 20.

所以类似:

>  maxBound :: Int  
9223372036854775807  
>  (maxBound :: Int) + 1  
-9223372036854775808  
>  (maxBound :: Int) + 2  
-9223372036854775807  
>  let x = (maxBound :: Int) + 1 in x + x
0
Run Code Online (Sandbox Code Playgroud)

为什么"允许"这种情况发生?简单 - 效率.不检查是否存在整数溢出要快得多.这就是Integer存在的原因- 它是无限的,因为当你认为你可能会溢出,但你付出了效率的代价.

[0] http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-Int.html

  • 两个补码的巧妙之处在于它允许这种"环"结构仍然存在.取最高正数,`0111`,然后加一,你得到'1000`,最低负数.从那时起你就算数了; 在`1111`,你在-1,再加一个,你得到'0000`(零). (4认同)
  • 一个小问题 - 在大多数CPU架构中,您描述的有符号整数的系统(偏移二进制)实际上并不常见.在大多数现代架构中,最低的负数实际上通常是"100 ......".见http://en.wikipedia.org/wiki/Signed_number_representations和http://en.wikipedia.org/wiki/Two%27s_complement (3认同)
  • @贾斯汀L。绝对,我从来没有听说过最低的数字都是空位。这可能是对海报的误解。检查 `shiftR (maxBound :: Int) 63` 应该给出 0,而不是 `minBound+1`。 (2认同)