因此,我正在制作一个素数列表,以帮助我使用简单的试验部门学习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>>
。有谁知道问题是什么?
答案 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执行。