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

时间:2013-07-20 20:31:48

标签: haskell types integer

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

factorial :: Int -> Int
factorial n = product [1..n]

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

ghci> factorial 50
-3258495067890909184

请注意

ghci> maxBound :: Int
9223372036854775808

因为我在64位上运行。

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

1 个答案:

答案 0 :(得分:19)

Int类型定义为“具有至少范围[-2 ^ 29 .. 2 ^ 29-1]的固定精度整数类型。” [0]范围因机器而异,但您可以使用minBoundmaxBound

找到它

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

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

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

例如,011 + 1100

现在,如果你是天真的(正如Haskell所做的那样)当没有次最重要的数字时执行此操作,那么它只是像往常一样递增,但是“让它头部被切断”。例如。 111 + 1变为000而不是1000。这就是Haskell所发生的事情,除了其最低值(表示为一系列0 s)是其最低负数。它使用其“最左边”位来表示+/- 。您需要(maxBound :: Int) + (maxBound :: Int) + 2才能获得0。

同样如此:

>  maxBound :: Int  
9223372036854775807  
>  (maxBound :: Int) + 1  
-9223372036854775808  
>  (maxBound :: Int) + 2  
-9223372036854775807  
>  let x = (maxBound :: Int) + 1 in x + x
0

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

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