我必须在Haskell中为一个项目实现Eratosthenes筛选的经典问题。而不是计算每个素数我只需要比较列表之间的数字。例如,我传递了一个潜在素数列表(参数1)和一个复合列表(列表2)。列表sieve [2..10] []
的结果为[2,3,5,7]
。
我认为我非常接近并且它编译,但它将每个项目都附加到主要列表而不是丢弃复合材料。我的想法是,它将采用所有数字2..10
或其他任何数据的列表x,并且复合材料列表y使用elem
来查看列表x的列表是否在列表y中找到,如果是,则附加到列出z并打印。提前谢谢!
目前我的代码返回第一个列表中的所有内容并拒绝排序。 sieve [2..10] []
会产生[2,3,4,5,6,7,8,9,10]
sieve ::[Int]->[Int]->[Int]
z = []
sieve [] [] = []
sieve x [] = x
sieve [] y = y
sieve xs ys = if ((elem (head xs)) ys) then (sieve (tail xs) ys)
else ((head xs):z)
答案 0 :(得分:1)
您展示的程序没有多大意义,首先将始终使用sieve x []
,此外,您应检查元素是否可被其他列表分割。最后,您应该使调用是递归的,而head xs : z
则不需要这样做,因为z
被定义为空列表。
让我们从基本情况开始:如果左侧列表为空,则无论第二个列表的内容如何,都会返回空列表。筛选什么都不会导致任何结果:
sieve [] _ = []
接下来,我们使用as pattern:
来寻找归纳案例sieve (x:xs) ds = ...
现在我们需要枚举已找到的元素列表。从找到的元素的any
分钟x
开始,我们就知道数字不是(相对)素数。这种情况形式化为:
(==) 0 . mod x :: Integral b => b -> Bool
或者迭代ds
列表:
any ((==) 0 . mod x) ds
如果存在这样的元素,我们只需跳过元素,并使用sieve xs ds
调用归纳案例。
如果没有这样的元素,我们将它添加到ds
列表并发出它。结果是:x : sieve xs (x:ds)
。因此,归纳案例是:
sieve (x:xs) ds | any ((==) 0 . mod x) ds = sieve xs ds
| otherwise = x : sieve xs (x:ds)
我们可以通过为sieve xs
:
sieve (x:xs) ds | any ((==) 0 . mod x) ds = rec ds
| otherwise = x : rec (x:ds)
where rec = sieve xs
因此完整的功能是:
sieve [] _ = []
sieve (x:xs) ds | any ((==) 0 . mod x) ds = rec ds
| otherwise = x : rec (x:ds)
where rec = sieve xs
您可以通过两种方式提升效果:
在x
末尾添加ds
。这确实是一项更昂贵的操作。但过了一段时间,你不经常添加数字。这很有意思,因为在这种情况下ys
看起来像[2,3,5,7,11]
而不是[11,7,5,3,2]
。现在,2
(50%)可以对一个数字进行整除的可能性大于可被11
整除的数字(9.9%)。最好尝试尝试最有可能成功的测试。
此外,您可以在到达要测试的数字的平方根的分隔符后结束检查:如果某个数字不能被小于该数字的数字整除,则它绝对不能被数字整除大于平方根。
因此,更有效的方法是:
sieve [] _ = []
sieve (x:xs) ds | any ((==) 0 . mod x) $ takeWhile (\y -> y*y <= x) ds = rec ds
| otherwise = x : rec (ds++[x])
where rec = sieve xs
答案 1 :(得分:1)
你所谓的sieve
通常称为minus
,从第一个列表中减去第二个列表,假设两者都是有序的,增加了数字列表。那么仅仅比较两个头元素就足够了,没有任何elem
个调用。
但如果您为z
提供了正确的定义,它仍然有用。 z=[]
只是一个占位符,可以编译(对吗?);这不是正确的定义。应该是:
sieve :: [Int] -> [Int] -> [Int]
-- z = []
sieve [] [] = []
sieve x [] = x
sieve [] y = y
sieve xs ys = if ((elem (head xs)) ys) then (sieve (tail xs) z)
else ((head xs) : sieve (tail xs) ys )
where
z = ... -- need to remove (head xs) from ys
对于最后一条评论的任务,您可以使用例如delete
功能。
这仍然不会产生没有复合列表的素数列表,因此初始调用不可以将第二个列表清空(否则,首先会得到相同的正如你所做的那样,因为sieve x [] = x
方程式):
primesAmong input = sieve input composites
但是composites
是什么? Eratosthenes的答案是,为什么,它们是素数的倍数!(和试验分子说:复合材料有其他素数作为它们的除数)。
鉴于素数,比如说2,我们只计算: 2,4,6,... ;对于3,比方说,它是 3,6,9,12,...... ;找到它的倍数。让我们把它写下来:
composites = mutliplesOf primes
mutliplesOf primes = [ mult | p <- primes, mult <- [...] ]
这不太合适:这个multiplesOf
需要一个参数:
primes = primesAmong input
primesAmong input = sieve input (mutliplesOf primes)
我们似乎在追逐自己的尾巴;我们还没有primes
;我们可以用什么呢?找到多个非素数以及素数是否有害?
确实有正在运行的代码之后,尝试找一种方法来使用primes
。