Toward the end of class Luis Fisher asked if instead of generating a list of primes (as we do in the sieve shown in Project 1) we could generate a list of all the integers, each marked as either prime or non-prime. Here's a function that does that.
-- Generate the infinite list of integers starting at 2 and the (infinite) list of primes.
-- Pass both lists to p_and_np
primes_and_nonprimes = p_and_np [2 ..] primes
-- primes is the function from Project 1 that generates primes.
data PNP = Prime | NonPrime deriving Show -- This is equivalent to declaring Prime and NonPrime
-- as an enumerated data type. The reason to do this
-- is to make it possible to print Prime and NonPrime
-- without making them Strings.
-- Walk down the two lists together.
-- If the first elements are equal, the number is a prime.
Go on to the rest of both lists.
-- Otherwise the first element of the integer list is not a prime.
-- Go on to the next element of the integer list, but keep the prime list unchanged.
p_and_np (i:is) (p:ps)
| i == p = (i, Prime) : p_and_np is ps
| otherwise = (i, NonPrime) : p_and_np is (p:ps)
> take 20 primes_and_nonprimes
[(2,Prime),(3,Prime),(4,NonPrime),(5,Prime),(6,NonPrime),(7,Prime),(8,NonPrime),(9,NonPrime),(10,NonPrime),(11,Prime),(12,NonPrime),(13,Prime),(14,NonPrime),(15,NonPrime),(16,NonPrime),(17,Prime),(18,NonPrime),(19,Prime),(20,NonPrime),(21,NonPrime)]