module ProjectEuler ( isPrime, primeSieve, lcmm, digitSum, sumProperDivisors, countDivisors, isPandigital, ) where import Data.Char (digitToInt) import Data.List (nub) import Data.List.Ordered (minus, unionAll) isPrime :: (Integral n) => n -> Bool isPrime 1 = False isPrime 2 = True isPrime 3 = True isPrime n = n > 0 && odd n && n `mod` 3 /= 0 && null [x | x <- candidates, n `mod` x == 0 || n `mod` (x + 2) == 0] where candidates = [5, 11 .. limit] limit = floor (sqrt (fromIntegral n)) + 1 primeSieve :: (Integral n) => [n] primeSieve = 2 : 3 : [5, 7 ..] `minus` unionAll [[p * p, p * p + 2 * p ..] | p <- tail primeSieve] lcmm :: (Integral n) => [n] -> n lcmm values | length values == 2 = lcm (head values) (last values) | otherwise = lcm (head values) (lcmm (tail values)) digitSum :: (Integral a, Show a) => a -> Int digitSum n = sum $ map digitToInt $ show n sumProperDivisors :: (Integral a) => a -> a sumProperDivisors n = sum [if x /= y then x + y else x | x <- [2 .. floor $ sqrt $ fromIntegral n], let { y = n `div` x }, n `mod` x == 0] + 1 countDivisors :: (Integral a) => a -> Int countDivisors n = length $ nub $ concat [[x, n `div` x] | x <- [1 .. limit], n `mod` x == 0] where limit = floor $ sqrt $ fromIntegral n isPandigital :: Integer -> Bool isPandigital n = n_length == length (nub n_char) && '0' `notElem` n_char && digitToInt (maximum n_char) == n_length where n_char = show n n_length = length n_char