在用Haskell实现的Eratosthenes的Sieve中,为什么未从列表中删除3,5,7 ..的倍数?

时间:2018-07-29 18:48:04

标签: haskell primes sieve-of-eratosthenes

我目前正在自学Doets和Eijck撰写的《 逻辑,数学和编程的Haskell道路》 ,我正在学习第3章。

在本章中,作者为实现Eratosthenes的Sieve筛网算法提供了Haskell代码,我不喜欢它们的实现,因此我尝试给出自己的实现。但是,我的代码版本只删除了2的倍数,我不知道是什么原因。这里是代码:

sieve :: [Int] -> [Int]
sieve (0:xs) = sieve xs
sieve (x:xs) = x : sieve (mark x 2 xs)
 where
 mark :: Int -> Int -> [Int] -> [Int]
 mark n k (y:ys)
  | y == n*k = 0 : (mark n (k+1) ys)
  | otherwise = y : (mark n (k) ys) 

输出为

*Ch3> sieve [2..]
[2,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,...

所以,为什么代码不对其他数字(例如3、5、7。)的倍数执行相同的删除操作??

1 个答案:

答案 0 :(得分:7)

  

简短的回答:k中的计数器mark对于n> 2不会递增。

mark x 2 [2..]正确地从列表中删除了偶数,因此下一步就是调用sieve [3,5..],它等于3:sieve (mark 3 2 [5,7..]),所以让我们看看这里发生了什么。

mark 3 2 [5,7..](大概)尝试从列表中删除3的所有倍数,但是它是分步进行的,首先尝试从列表中删除6。但是,由于列表仅包含奇数,因此6不会从列表中删除,并且第一种情况总是失败。代码继续检查6,从不删除9。

类似地,从不删除25,因为该代码仅尝试从列表中删除2*5