My own implementation uses power set of prime factors now.
For example, to get list of divisors of 30
, which prime factor is [2,3,5]
,
- make the power set of prime factors,
[[],[2],[3],[5],[2,3],[2,5],[3,5],[2,3,5]]
- product each elements and get result
[1,2,3,5,6,10,15,30]
, which is list of divisors of 30
Code:
divisors :: Integral a => a -> [a]
divisors n
| n < 1 = []
| otherwise = distinct $ map product $ (powerset . factors) n
-- | remove duplicated element in a list
distinct :: Eq a => [a] -> [a]
distinct [] = []
distinct (x : xs)
| x `elem` xs = distinct xs
| otherwise = x : distinct xs
-- | generate power set of a list
powerset :: [a] -> [[a]]
powerset [] = [[]]
powerset (x : xs) = xss ++ map (x :) xss where xss = powerset xs
-- | generate prime factors of a integer
factors :: Integral a => a -> [a]
factors m = f m (head primes) (tail primes) where
f m n ns
| m < 2 = []
| m < n ^ 2 = [m]
| m `mod` n == 0 = n : f (m `div` n) n ns
| otherwise = f m (head ns) (tail ns)
-- | prime sequence
primes :: Integral a => [a]
primes = 2 : filter (\n-> head (factors n) == n) [3,5..]
In this code, duplicated divisors appear if duplicated prime factors exist.
I remove duplicated divisors at last step, but it does not fix basic cause of duplication.
I feel sure that there are more smart ways.
Note:
Update:
Thanks to comingstorm's advice, I studied more about Data.List module and update my code:
import Data.List (group, subsequences)
divisors :: Integral a => a -> [a]
divisors = map product . concatMap sequence . subsequences . map (scanr1 (*)) . group . factors
primes = ... -- same as before
factors m = ... -- same as before
I noticed that distinct
and powerset
in original code are same with nub
and subsequences
in Data.List module.
It becomes simple but behzad.nouri's code is much faster.