Debugging 帮助调试Haskell中的大数异常takeWhile行为
首先,为这个模糊的标题道歉,但我不确定我到底在问什么(!) 在大学遇到Haskell之后,我最近开始愤怒地使用它,所以我把它当作一个扩展的Hello World来解决问题,真的。在我的一个答案中,我遇到了一个错误,它似乎表明我对语言的一个基本部分有误解,而这不是我从教程中可以解决的问题,也不是我知道的足以开始用谷歌搜索的问题 问题本身的简要描述-解决方案与素数有关,因此我想要一个无限素数列表,我实现了它(还没有优化!): 由于无限列表的计算可能有点繁琐,我当然会使用惰性计算来确保只计算我想要的位。例如,我可以向GHCI询问小于100的素数:Debugging 帮助调试Haskell中的大数异常takeWhile行为,debugging,haskell,integer,Debugging,Haskell,Integer,首先,为这个模糊的标题道歉,但我不确定我到底在问什么(!) 在大学遇到Haskell之后,我最近开始愤怒地使用它,所以我把它当作一个扩展的Hello World来解决问题,真的。在我的一个答案中,我遇到了一个错误,它似乎表明我对语言的一个基本部分有误解,而这不是我从教程中可以解决的问题,也不是我知道的足以开始用谷歌搜索的问题 问题本身的简要描述-解决方案与素数有关,因此我想要一个无限素数列表,我实现了它(还没有优化!): 由于无限列表的计算可能有点繁琐,我当然会使用惰性计算来确保只计算我想要的位
*Main> takeWhile (< 100) primes
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]
*Main>takeWhile(<100)素数
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]
现在有一部分我一点也不明白-当上限足够大时,我根本没有得到答案。特别是:
*Main> takeWhile (< 4000000000) primes
[]
*Main>takeWhile(<4000000000)素数
[]
这不是takeWhile
本身的问题,也不是部分应用的函数的问题,因为takeWhile(<4000000000)[2..]
正如我所期望的那样工作。我使用filter(在primes
的定义中)没有问题,因为takeWhile(<4000000000)(filter-偶[2..])
也会返回预期的结果
通过二进制搜索,我发现有效的最大上限是2^31-1
,因此这显然意味着某种基于空间的约束(即最大的正符号整数)。然而:
2
来自filter偶数[2..]
时,谓词返回true;我知道primes
返回2
作为其第一个元素。那么我的列表怎么可能是空的,这个谓词怎么会“对于2的某些值”失败呢如果有任何想法,我都会很感激,因为我没有足够的经验知道从哪里开始。感谢您花时间查看。haskell中有两种内置的整数类型:
Int
和Integer
<代码>整数是默认值,没有限制<代码>整数但是是有界的。由于您在isPrime
4000000000的类型中显式使用Int
,因此isPrime4000000000被用作Int
和溢出。如果您将isPrime
的类型更改为Integer->Bool
或更好的Integral a=>a->Bool
(读:一个可以接受任何类型的Integral
值并返回Bool
的函数),它将按预期工作
这里需要注意的重要一点(除了Int
和Integer
之间的区别)是4000000000的类型取决于它的使用方式。如果它用作接受Int
的函数的参数,则它将是Int
(在32位系统上,它将溢出)。如果将其用作接受整数的函数的参数,则它将是整数(且永不溢出)。如果它被用作接受任何类型的积分的函数的参数,它也将是一个整数
,因为整数
是积分的默认实例,这是一个简单的答案(…我看到已经部分回答)-“过早的专门化”
定义的第一部分“类型签名”指定:
isPrime :: Int -> Bool
Int
不仅仅是表示Integer
的“快捷方式”—它们是不同的类型!要成为挑剔的人(这反过来又会让其他人把我不准确的地方撕碎),这里有从不“不同的2
”值-它必须是Int类型,因为这就是您指定函数的方式(将2与函数的参数n
进行比较,并且只允许比较相同类型的值,因此2
被“固定”到Int
类型
哦,作为一个警告,Int类型是一种很有可能出现大小写的类型。如果您的系统是在64位环境中构建的,那么您的Int
也将基于64位表示,并且您的示例将工作到2^63-1,而不是像您那样的2^31-1。请注意我的措辞:我有一台带有MS Windows的64位计算机操作系统,这意味着还没有正式的64位MinGW工具链-我的操作系统是64位的,但我的GHC版本是用32位库编译的,所以它有32位的Int
s。当我使用Linux时,即使在虚拟机中,它也有64位的工具链,所以Int
s是64位的。如果你使用了其中一个库,你可能没有注意到行为
所以,我想这只是在对你的类型进行推理时要小心的另一个原因。(尤其是在Haskell,无论如何…)谢谢,我现在明白了。所以事实证明,它确实是2
的不同值-Int
vsInteger
!这导致类型推断将字符串4000000000
解释为两种情况下的不同数据类型,后者是Int
,因此有几百个负值百万,谢谢
isPrime :: Int -> Bool