module AntiPrimes
(Nui, Siz, Lst, size, dividers, proof, list) where
import Data.List (foldr1, group, nub, sort, tails)
import Data.Numbers.Primes (primeFactors)
type Nui = Int
type Siz = Int
type Lst = [(Nui, Siz)]
frequ :: [Int] -> [(Int, Int)]
frequ list = map (\l -> (head l, length l)) (group (sort list))
comb :: (Eq a, Num a) => a -> [a1] -> [[a1]]
comb 0 lst = [[]]
comb n lst = do
(x:xs) <- tails lst
rest <- comb (n1) xs
return $ x:rest
combAll :: (Eq a, Num a) => a -> [a1] -> [[a1]]
combAll 0 lst = []
combAll n lst = (comb n lst) ++ (combAll (n1) lst)
msg :: String
msg = "the number must be greater than 0"
lst1 :: Lst
lst1 = [(1,1)]
mul :: (Num a, Foldable t) => t a -> a
mul x = foldr1 (*) x
tup :: Nui -> (Nui, Siz)
tup n = (n, size n)
lst :: Nui -> Lst
lst n
| n <= 0 = error msg
| n == 1 = lst1
| otherwise = map tup rng
where rng = [2..n]
size :: Nui -> Siz
size n
| n <= 0 = error msg
| n == 1 = 1
| otherwise = foldr1 (*) incrs
where facts = primeFactors n
frequs = frequ facts
counts = map snd frequs
incrs = map (1 +) counts
dividers :: Nui -> [Int]
dividers n
| n <= 0 = error msg
| n == 1 = [1]
| otherwise = sort add1
where facts = primeFactors n
len = length facts
combs = combAll len facts
multi = map mul combs
clean = nub multi
add1 = clean ++ [1]
proof :: Nui -> Bool
proof n
| n <= 0 = error msg
| n == 1 = True
| n == 2 = True
| otherwise = length flt == 1
where siz = size n
flt = filter (\(a, b) -> b >= siz) $ lst n
list :: Int -> Lst
list 0 = error msg
list 1 = lst1
list n
| n <= 0 = error msg
| n == 1 = lst1
| otherwise = list' lst1 (lst n)
list' :: Lst -> Lst -> Lst
list' aps [] = aps
list' aps rest = list' nxt est
where top = head rest
rst = tail rest
nxt = aps ++ [top]
est = filter (\(a, b) -> b > (snd top)) $ rst