问题
I have a recursive definition of sieve
in Haskell for prime number computation. But I don’t know how to write the same function using higher–order functions such as map
or filter
. Can anybody show me please?
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
回答1:
With map
and filter
and iterate
; very slow:
primes = map head $ iterate (\(x:xs)-> filter ((> 0).(`rem`x)) xs) [2..]
with addition of concat
; much faster and with much improved complexity:
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..]))
more at http://www.haskell.org/haskellwiki/Prime_numbers_miscellaneous#One-liners.
You can express iterate
through map
if you prefer:
iterate f x = let r = x : map f r in r
and filter
too:
filter f xs = concat $ map (\x -> [x | f x]) xs
But for the true sieve of Eratosthenes, - one which does not detect composites by divisibility testing but generates them directly from primes it finds, and finds the primes in gaps between thus generated composites, - we need some more auxiliary functions, like minus and union, and treelike-folding foldi (foldr
can be used in place of foldi
but with decreased speed and worsened complexity):
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)
This runs yet faster, at close to best empirical orders of growth achievable with Haskell's immutable code. Immutable arrays can be faster, but they are excluded here because a. it's not in the question, and b. their performance is determined by a given Haskell implementation, not a user code. Mutable arrays are of course the fastest but the code is even more involved.
回答2:
I threw this together quickly, the speed isn't that great, but it is really easy to implement.
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.
来源:https://stackoverflow.com/questions/20393703/how-do-i-define-the-sieve-function-for-prime-computation-using-higher-order-func