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 Haskell wiki.
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.