Given a number n is dividable by k, then n/k is a divisor of n as well. Indeed, since n/(n/k)=k. If k>√n, we thus know that k/n<√n, and therefore, instead of calculating all the divisors, we can each time we find a divisor, yield the "co-divisor" as well.
We thus can implement the algorithm as follows:
divisors :: Integral a => a -> [a]
divisors n = concatMap f (filter ((==) 0 . mod n) (takeWhile (\k -> k*k <= n) [1 .. n]))
where f k | k < l = [k, l]
| otherwise = [k]
where l = div n k
Here we thus first use takeWhile (\k -> k*k <= n) [1 .. n]
to create a list from 1
until (and including if it is integral) √n
).
Next we filter these elements, and only retain those that divide n
. Finally for each of these elements, we check if the co-divisor is different. If that is the case, we both yield k
and the co-divisor l
, otherwise (this will only be the case for √n
), we only yield k
.
For example:
Prelude Data.List> divisors 1425
[1,1425,3,475,5,285,15,95,19,75,25,57]