Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Does Not Evaluate Lazily takeWhile

isqrt :: Integer -> Integer
isqrt = floor . sqrt . fromIntegral

primes :: [Integer]
primes = sieve [2..] where
 sieve (p:ps) = p : sieve [x | x <- ps, x `mod` p > 0]

primeFactors :: Integer -> [Integer]
primeFactors n = takeWhile (< n) [x | x <- primes, n `mod` x == 0]

Here is my code. I think you guessed what I am trying to do: A list of prime factors of a given number using infinite list of prime numbers. But this code does not evaluate lazily.

When I use ghci and :l mycode.hs and enter primeFactors 24, the result is [2, 3 ( and the cursor constantly flashing there) there isn't a further Prelude> prompt. I think there is a problem there. What am I doing wrong?

Thanks.

like image 411
D. Jones Avatar asked Aug 08 '16 10:08

D. Jones


Video Answer


1 Answers

takeWhile never terminates for composite arguments. If n is composite, it has no prime factors >= n, so takeWhile will just sit there.

Apply takeWhile to the primes list and then filter the result with n mod x, like this:

primeFactors n = [x | x <- takeWhile (<= n) primes, n `mod` x == 0]

(<= is used instead of < for maximum correctness, so that prime factors of a prime number would consist of that number).

like image 166
n. 1.8e9-where's-my-share m. Avatar answered Nov 15 '22 06:11

n. 1.8e9-where's-my-share m.