List 埃拉托斯烯Haskell筛及复合材料列表

List 埃拉托斯烯Haskell筛及复合材料列表,list,haskell,primes,sieve-of-eratosthenes,List,Haskell,Primes,Sieve Of Eratosthenes,我必须为一个项目在Haskell中实现Eratosthenes筛的经典问题。我不需要计算每个素数,只需要比较列表中的数字。例如,我传递了一个潜在素数列表(参数1)和一个组合列表(列表2)筛选[2..10][]结果与列表[2,3,5,7] 我认为我非常接近,它可以编译,但它会将每一项附加到主列表中,而不是扔掉组合。我的想法是,它需要所有数字的列表x2..10或任何东西,复合列表y使用elem来查看列表x的头是否在列表y中,如果是,则附加到列表z并打印。提前谢谢 目前,我的代码返回第一个列表中的所有

我必须为一个项目在Haskell中实现Eratosthenes筛的经典问题。我不需要计算每个素数,只需要比较列表中的数字。例如,我传递了一个潜在素数列表(参数1)和一个组合列表(列表2)<代码>筛选[2..10][]结果与列表
[2,3,5,7]

我认为我非常接近,它可以编译,但它会将每一项附加到主列表中,而不是扔掉组合。我的想法是,它需要所有数字的列表x
2..10
或任何东西,复合列表y使用
elem
来查看列表x的头是否在列表y中,如果是,则附加到列表z并打印。提前谢谢

目前,我的代码返回第一个列表中的所有内容,并拒绝排序<代码>筛选[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)

您显示的程序没有多大意义,首先将始终使用
sieve x[]
,此外,您应该检查一个元素是否可被另一个列表整除。最后,您应该使调用递归,因为
z
被定义为空列表,所以不能使用
headxs:z
执行此操作

让我们从基本情况开始:如果左侧列表为空,则不管第二个列表的内容如何,都会返回空列表。由于筛选不产生任何结果:

sieve [] _ = []
下一步,我们寻找感应情况,使用as模式:

sieve (x:xs) ds = ...
现在我们需要枚举已经找到的元素列表。从找到的元素中的任何一个可以除x的那一刻起,我们就知道这个数字不是(相对)素数。该条件形式化为:

(==) 0 . mod x :: Integral b => b -> Bool
或在
ds
列表上迭代:

any ((==) 0 . mod x) ds
如果存在这样的元素,我们只需跳过该元素,并使用
sieve xs ds
调用归纳案例

如果没有这样的元素,我们将其添加到
ds
列表中并发出它。结果是:
x:sievexs(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
您可以通过两种方式提高性能:

  • ds
    末尾添加
    x
    。这确实是一项更昂贵的行动。但过了一段时间,你就不会经常添加数字了。这很有趣,因为在这种情况下,
    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
sieve[].[]

sieve(x:xs)ds | any(==)0.mod x)$takeWhile(\y->y*y你称之为
sieve
通常被称为
,从第一个列表中减去第二个列表,假设这两个列表都是有序的,增加数字列表。然后只比较两个head元素就足够了,没有任何
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
对于最后一条评论的任务,您可以使用例如function

如果没有复合列表,这仍然无法生成素数列表,因此初始调用不能在第二个列表为空的情况下进行(否则,由于
sieve x[]=x
等式,您将得到与您相同的第一个参数):

但是什么是复合材料呢?埃拉托什内斯的答案是,为什么,它们是素数的倍数!(试算法说:复合材料有其他素数作为其除数)

给定一个素数,比如说2,我们只是数数:2,4,6,…;对于3,比如说,它是3,6,9,12,…;求它的倍数。我们把它写下来:

composites = mutliplesOf primes
mutliplesOf primes = [ mult | p <- primes, mult <- [...] ]
我们似乎在追逐自己的尾巴;我们还没有
素数
;我们可以用什么来代替呢?找到非素数和素数的倍数有什么害处吗


在你有了一个运行的代码之后,试着找到一种使用
素数的方法。

你对
sieve[2..10][
模式的调用与定义
sieve x[]相匹配=x
,因此没有使用
sieve
的其他子句。您显示的程序没有多大意义,首先是
sieve x[]
将始终被使用,此外,在中,你应该检查一个元素是否可以被另一个列表整除。最后,你应该使调用递归,这是你不能用
头xs:z
做的,因为
z
被定义为空列表。不能在Eratosthenes的筛子中执行整除性检查!!@WillNess:then(a)为什么使用可分性检查,(b)如果在大多数应用程序中将元素添加到
ys
,元素将更小,因此筛子将允许所有元素;以及(3)这篇维基文章明确指出。你确实可以实现一个版本,其中复合物是为
ys
计算的,但这会降低算法的性能。@CommuSoft(a)不是一个埃拉托什尼的筛子,而是一个试用除法的筛子。(b)不理解你,抱歉。(c)是的,它说“它经常与埃拉托斯烯筛相混淆”也就是说,它不是埃拉托斯烯筛,而是因为它而混淆。如果你还没有看到,也许它会是一本有趣的读物。:)非常好的解释-但我认为结果的顺序是错误的(这可能是一个问题,也可能不是一个问题)
composites = mutliplesOf primes
mutliplesOf primes = [ mult | p <- primes, mult <- [...] ]
primes = primesAmong input
primesAmong input = sieve input (mutliplesOf primes)