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

标签 haskell types integer

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

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

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

ghci> factorial 50
-3258495067890909184

请注意

ghci> maxBound :: Int
9223372036854775808

因为我在 64 位上运行。

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

最佳答案

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)是它的最小负数。它使用它的“最左边”位来表示+/-。您需要执行 (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

关于haskell - Haskell 中可疑的 'Int' 与 'Integer' 处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17766424/

相关文章:

haskell - 动态获取某个类型的数据构造函数列表

java - 将 HashMap<Integer, Long> 转换为 HashMap<Integer, Integer>

java - TODO-FIXME : In Java 8's Integer class?

javascript - 如何同时读取 1 个标志位并获取整数

haskell |努力理解类型声明和缩写

haskell - 评估策略

types - 如何在 Kotlin 中使用递归类型

haskell - 为什么 Haskell 不泛化一些函数

haskell - 如何设置 haskell-mode 来生成标签?

haskell - 如何使用foldr/foldl定义foldM(如果可能的话)?