In Haskell, if you use a drive to create a list, but ultimately need to cancel it, it often happens that it is better to reset the drive and instead create a list lazily as a result of your calculation.
If you apply such thinking to the search for primes and take full advantage of laziness, you get the well-known technique of creating an endless list of all primes. If we reorganize your code as little as possible to use this technique, we will get something like:
allPrimes = [2, 3] ++ aux 5 where aux suspect = let currentIsPrime = foldl (\ln -> l && suspect `mod` n /= 0) True $ takeWhile (\n -> n*n <= suspect) allPrimes in case currentIsPrime of True -> suspect : aux (suspect + 2) False -> aux (suspect + 2) nthPrime n = allPrimes !! (n-1)
Now I deleted the unnecessary parameters and changed the code to accumulate in lazy production and used my own result as a source of simple divisors for testing (this is called "node binding"). Other than that, the only change is to add a takeWhile check: since the list we are testing, the divisors from is defined in terms of itself and is infinite to load, we need to know where in the list to stop the divisors checking, so we donβt get truly infinite recursion.
In addition, there is inefficiency in this code:
foldl (\ln -> l && suspect `mod` n /= 0) True
It is not a good way to check if there are any divisors in the list, because, as it is written, it does not stop as soon as the divisor is found, even if && cuts itself (stops as soon as its first argument turns out to be False ).
To ensure the correct layout, instead of foldr you can use
foldr (\nr -> suspect `mod` n /= 0 && r) True
Or, even better, use the predefined function all :
all (\n -> suspect `mod` n /= 0)
Using my comments
Here's what it would look like if you use all and reorganize it a bit:
allPrimes :: [Integer] allPrimes = 2 : 3 : aux 5 where aux suspect | currentIsPrime = suspect : nextPrimes | otherwise = nextPrimes where currentIsPrime = all (\n -> suspect `mod` n /= 0) $ takeWhile (\n -> n*n <= suspect) allPrimes nextPrimes = aux (suspect + 2) nthPrime :: Int -> Integer nthPrime n = allPrimes !! (n-1)