Haskell递归列表理解导致C Stack Overflow

时间:2011-03-04 21:19:22

标签: haskell recursion stack-overflow list-comprehension hugs

因此,我正在制作一个素数列表,以帮助我使用简单的试验部门学习haskell(直到我的语言变得更好,没有花哨的东西)。我正在尝试使用以下代码:

primes = 2 : [ x | x <- [3..], all (\p -> (mod x p) /= 0) primes]

加载时没有错误。但是:

>take 2 primes
[2ERROR - C stack overflow

我尝试使用嵌套列表推导相同的东西。它不起作用。我猜我会做太多的递归调用,但如果我只计算一个素数,那就不应该这样了。在我看来,懒惰的评估应该使take 2 primes做出类似的事情:

primes = 2 : [ 3 | all (\p -> (mod 3 p) /= 0) [2] ]

这不需要那么多计算 - mod 3 2 == True,所以all (\p -> (mod 3 p) /= 0) == True,这意味着take 2 primes == [2, 3],对吗?我不明白为什么这不起作用。希望有更多精通函数式编程黑魔法的人可以帮助我...

这是在HUGS,如果这有任何区别。

编辑 - 我能够提出这个解决方案(不太漂亮):

primes = 2 : [ x | x <- [3..], all (\p -> (mod x p) /= 0) (takeWhile (<= (ceiling (sqrt (fromIntegral x)))) primes)]

EDIT2-当通过HUGS或GHCi解释时程序工作正常,但是当我尝试用GHC编译它时,它输出test: <<loop>>。有谁知道问题是什么?

3 个答案:

答案 0 :(得分:7)

拥抱不应该这样做,但无论如何代码都会被破坏,所以无关紧要。考虑:

primes = 2 : [ x | x <- [3..], all (\p -> (mod x p) /= 0) primes]

你如何确定3是否是素数?好吧,mod 3 2 == 0?不是。mod 3 ??? == 0? OOPS!两个之后素数的下一个要素是什么?我们不知道,我们正在努力计算它。在测试了所有小于x的p elem素数后,您需要添加一个添加3(或任何其他sqrt x)的排序约束。

答案 1 :(得分:3)

所有人的文档都说“为了结果为真,列表必须是有限的” http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:all

答案 2 :(得分:0)

之前的答案解释了为什么原始理解不起作用,而不是如何编写一个可行的理解。

这是一个列表理解,递归地,懒惰地(虽然没有效率)计算所有素数:

let primes = [x | x <- 2:[3,5..], x == 2 || not (contains (\p -> 0 == (mod x p)) (takeWhile (\b -> (b * b) < x) primes))]

显然,我们不需要检查所有质数的mod x p,我们只需要对低于潜在素数的sqrt的质数进行检验。这就是takeWhile的用途。原谅(\b -> (b * b) < x)这应该等同于(< sqrt x),但Haskell类型系统不喜欢这样。

在我们向列表中添加任何元素之前,x == 2会阻止takeWhile执行。