RosettaCodeData/Task/Zumkeller-numbers/Haskell/zumkeller-numbers.hs
2023-07-01 13:44:08 -04:00

73 lines
1.6 KiB
Haskell

import Data.List (group, sort)
import Data.List.Split (chunksOf)
import Data.Numbers.Primes (primeFactors)
-------------------- ZUMKELLER NUMBERS -------------------
isZumkeller :: Int -> Bool
isZumkeller n =
let ds = divisors n
m = sum ds
in ( even m
&& let half = div m 2
in elem half ds
|| ( all (half >=) ds
&& summable half ds
)
)
summable :: Int -> [Int] -> Bool
summable _ [] = False
summable x xs@(h : t) =
elem x xs
|| summable (x - h) t
|| summable x t
divisors :: Int -> [Int]
divisors x =
sort
( foldr
( flip ((<*>) . fmap (*))
. scanl (*) 1
)
[1]
(group (primeFactors x))
)
--------------------------- TEST -------------------------
main :: IO ()
main =
mapM_
( \(s, n, xs) ->
putStrLn $
s
<> ( '\n' :
tabulated
10
(take n (filter isZumkeller xs))
)
)
[ ("First 220 Zumkeller numbers:", 220, [1 ..]),
("First 40 odd Zumkeller numbers:", 40, [1, 3 ..])
]
------------------------- DISPLAY ------------------------
tabulated ::
Show a =>
Int ->
[a] ->
String
tabulated nCols = go
where
go xs =
let ts = show <$> xs
w = succ (maximum (length <$> ts))
in unlines
( concat
<$> chunksOf
nCols
(justifyRight w ' ' <$> ts)
)
justifyRight :: Int -> Char -> String -> String
justifyRight n c = (drop . length) <*> (replicate n c <>)