我目前正在自学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。)的倍数执行相同的删除操作??
答案 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
。