【发布时间】:2011-07-09 03:14:47
【问题描述】:
所以我正在制作一个素数列表,以帮助我使用简单的试除法学习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>>。有谁知道问题出在哪里?
【问题讨论】:
-
all (\p -> (mod x p) /= 0) primes不会终止,因为primes是一个无限序列。 -
但是在斐波那契数列的规范列表理解中使用了相同的想法(如果我理解正确的话)
fibonacci = 1 : 1 : [ a + b | (a, b) <- zip fibonacci (tail fibonacci) ] -
问题不在于使用无限列表,而是将
all与无限列表一起使用...验证任意无限列表的每个元素都满足某个谓词是不可能的跨度> -
转念一想,我应该使用
x <- [3..]而不是x <- [ (2 * i) + 1 | i <- [1..] ] -
“最好”的方法是The Genuine Sieve of Eratosthenes。但是“试验划分”方法(也在论文中描述)通常足以与 Haskell 一起玩。
标签: haskell recursion stack-overflow list-comprehension hugs