import Data.Numbers.Primes (primeFactors)
import Data.List (unfoldr)
import Data.Tuple (swap)
import Data.Bool (bool)

isSmith :: Int -> Bool
isSmith n = pfs /= [n] && sumDigits n == foldr ((+) . sumDigits) 0 pfs
  where
    sumDigits = sum . baseDigits 10
    pfs = primeFactors n

baseDigits :: Int -> Int -> [Int]
baseDigits base = unfoldr remQuot
  where
    remQuot 0 = Nothing
    remQuot x = Just (swap (quotRem x base))

lowSmiths :: [Int]
lowSmiths = filter isSmith [2 .. 9999]

lowSmithCount :: Int
lowSmithCount = length lowSmiths

main :: IO ()
main =
  mapM_
    putStrLn
    [ "Count of Smith Numbers below 10k:"
    , show lowSmithCount
    , "\nFirst 15 Smith Numbers:"
    , unwords (show <$> take 15 lowSmiths)
    , "\nLast 12 Smith Numbers below 10k:"
    , unwords (show <$> drop (lowSmithCount - 12) lowSmiths)
    ]