用于排除Eratosthenes筛选数字的Haskell代码未按预期工作

时间:2015-04-22 20:07:22

标签: algorithm haskell sieve-of-eratosthenes

我带来了以下Sieve of Eratosthenes实施:

sieve :: (Integral a) => [a] -> [a]
sieve [] = []
sieve (p:ps) = p:[x | x <- sieve ps, (rem x p) /= 0] 

primes :: (Integral a) => [a]
primes = sieve [2..100]

primes打电话gchi打印:

[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]

p 2 添加optimization step起始标记号,我最终得到以下代码:

sieve :: (Integral a) => [a] -> [a]
sieve [] = []
sieve (p:ps) = p:[x | x <- sieve ps, x > p ^ 2, (rem x p) /= 0] 

primes :: (Integral a) => [a]
primes = sieve [2..100]

但它会产生以下输出:

[2]

我是Haskell的新手,所以我很难理解为什么添加 x > p ^ 2 会产生这个结果。

你能否通过解释Haskell如何评估该表达式来发现我的错误?

2 个答案:

答案 0 :(得分:2)

你有

sieve [2..10]

扩展到

2 : [x1 | x1 <- sieve [3..10], x1 > 4, rem x1 2 /= 0]
    = 2 : [x1 | x1 <- 3 : [x2 | x2 <- sieve [4..10],
                                x2 > 9,
                                x2 `rem` 3 /= 0],
                x1 > 4,
                x1 `rem` 2 /= 0]

首先x13,但3 > 4False,所以我们转到下一个:

    = 2 : [x1 | x1 <- [x2 | x2 <- sieve [4..10],
                            x2 > 9,
                            x2 `rem` 3 /= 0],
                x1 > 4,
                x1 `rem` 2 /= 0]

    = 2 : [x1 | x1 <- [x2 | x2 <- 4 : [x3 | x3 <- sieve [5..10],
                                            x3 > 16,
                                            x3 `rem` 4 /= 0],
                            x2 > 9,
                            x2 `rem` 3 /= 0],
                x1 > 4,
                x1 `rem` 2 /= 0]

因此如果x24x2 > 9为false,那么我们将移至下一个元素:

    = 2 : [x1 | x1 <- [x2 | x2 <- [x3 | x3 <- sieve [5..10],
                                        x3 > 16,
                                        x3 `rem` 4 /= 0],
                            x2 > 9,
                            x2 `rem` 3 /= 0],
                x1 > 4,
                x1 `rem` 2 /= 0]

所以我们已经看到,我们知道返回的唯一实际值是23被跳过,因为3 > 4False4被跳过,但由于错误的原因,5将被跳过,因为5 > 16False,依此类推。这里的问题是您的条件x > p ^ 2会过滤整个列表,但您确实想要在列表中跳转。这意味着您实际感兴趣的值将从输出中过滤掉。

答案 1 :(得分:1)

这行代码:

p:[x | x <- sieve ps, x > p ^ 2, (rem x p) /= 0] 

说&#34;从sieve ps获取所有x,x > p^2x不能被p&#34;整除。这意味着所有小于或等于p^2的数字都会被丢弃。这显然不正确(最小的反例:[2..3])。