如何使用高阶函数定义用于素数计算的筛函数?

时间:2013-12-05 07:13:04

标签: haskell primes higher-order-functions map-function sieve

我在Haskell中有一个sieve的递归定义,用于素数计算。但我不知道如何使用高阶函数编写相同的函数,例如 mapfilter 。有人能告诉我吗?

sieve [] = []
sieve (x:xs) = check (x:xs)

check [] = []
check (x:xs)
        |x/=2 && x/=3 && x/=5 && x/=7 = comp (x:xs)
        |otherwise    = x : sieve xs

comp [] = []
comp (x:xs)
        |x `mod` 2 == 0 = sieve xs
        |x `mod` 3 == 0 = sieve xs
        |x `mod` 5 == 0 = sieve xs
        |x `mod` 7 == 0 = sieve xs
        |otherwise      = x : sieve xs

2 个答案:

答案 0 :(得分:1)

使用mapfilter以及iterate;很慢:

primes = map head $ iterate (\(x:xs)-> filter ((> 0).(`rem`x)) xs) [2..]

添加concat; 很多更快,复杂度也大大提高:

primes = concat $ map fst $ iterate (\(_,(p:ps,xs)) -> case span (< p*p) xs of
            {(h,t) -> (h,(ps, filter ((> 0).(`rem`p)) t))}) ([2],(primes,[3..]))

更多http://www.haskell.org/haskellwiki/Prime_numbers_miscellaneous#One-liners


如果您愿意,可以通过iterate表达map

iterate f x = let r = x : map f r in r

filter

filter f xs = concat $ map (\x -> [x | f x]) xs

但对于Eratosthenes的 true 筛子, - 一种不通过可分性测试检测复合物但是直接从它找到的素数生成它们,并在这样生成的复合物之间的间隙中找到素数, - 我们需要更多辅助功能,例如minus and uniontreelike-folding foldifoldr可以代替foldi,但速度降低,复杂性更差):

primes = 2 : _Y ((3:) . minus [5,7..]     
                         . foldi (\(x:xs) ys-> x : union xs ys) [] 
                            . map (\p-> [p*p, p*p+2*p..]))
_Y g = g (_Y g) 

运行速度更快,接近使用Haskell的不可变代码可实现的最佳empirical orders of growth。不可变数组可以更快,但它们被排除在这里,因为 a 。它不在问题中, b 。它们的性能由给定的Haskell实现决定,而不是用户代码。可变阵列当然是最快的,但代码更加复杂。

答案 1 :(得分:0)

我把它快速地放在一起,速度不是那么好,但它很容易实现。

primes'::[Int]->[Int]
primes' [] = []
primes' (x:xs) = x:primes (filter ((/= 0) . (`mod` x)) xs)

main = print $ primes [2..20] -- always input a contiguous list from 2 to N.