Question

To help me learn Haskell, I am working through the problems on Project Euler. After solving each problem, I check my solution against the Haskell wiki in an attempt to learn better coding practices. Here is the solution to problem 3:

primes = 2 : filter ((==1) . length . primeFactors) [3,5..]

primeFactors n = factor n primes
  where
    factor n (p:ps) 
        | p*p > n        = [n]
        | n `mod` p == 0 = p : factor (n `div` p) (p:ps)
        | otherwise      = factor n ps

problem_3 = last (primeFactors 317584931803)

My naive reading of this is that primes is defined in terms of primeFactors, which is defined in terms of primes. So evaluating primeFactors 9 would follow this process:

  1. Evaluate factor 9 primes.
  2. Ask primes for its first element, which is 2.
  3. Ask primes for its next element.
  4. As part of this process, evaluate primeFactors 3.
  5. Ask primes for its first element, which is 2.
  6. Ask primes for its next element.
  7. As part of this process, evaluate primeFactors 3.
  8. ...

In other words, steps 2-4 would repeat infinitely. Clearly I am mistaken, as the algorithm terminates. What mistake am I making here?

Was it helpful?

Solution

primeFactors only ever reads up to the square root of the number it's evaluating. It never looks further in the list, which means it never "catches up" to the number it's testing for inclusion in the list. Because Haskell is lazy, this means that the primeFactors test does terminate.

The other thing to remember is that primes isn't a function that evaluates to a list each time you access it, but rather a list that's constructed lazily. So once the 15th element has been accessed once, accessing it a second time is "free" (e.g. it doesn't require any further calculation).

OTHER TIPS

Kevin's answer is satisfactory, but allow me to pinpoint the flaw in your logic. It is #6 that is wrong. So we're evaluating primeFactors 3:

primeFactors 3          ==>
factor 3 primes         ==>
factor 3 (2 : THUNK)    ==>
2*2 > 3 == True         ==>
[3]

The THUNK need never be evaluated to determine that the primeFactor 3 is [3].

primeFactors 3 doesn't ask primes for its next element, only the first one, because 2*2 is greater than 3 already

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top