из модуля
>Data.Char
. Она принимает значение типа
>Char
и возвращает
>Int
:
>ghci> digitToInt '2'
>2
>ghci> digitToInt 'F'
>15
>ghci> digitToInt 'z'
>*** Exception: Char.digitToInt: not a digit 'z'
Функция >digitToInt
работает с символами из диапазона от >'0'
до >'9'
и от >'A'
до >'F'
(также и строчными).
Вот функция, принимающая число и возвращающая сумму его цифр:
>import Data.Char
>import Data.List
>digitSum :: Int -> Int
>digitSum = sum . map digitToInt . show
Преобразуем заданное число в строку, пройдёмся по строке функцией >digitToInt
, суммируем получившийся числовой список.
Теперь нужно найти первое натуральное число, применив к которому функцию >digitSum
мы получим в качестве результата число >40
. Для этого воспользуемся функцией >find
из модуля >Data.List
. Она принимает предикат и список и возвращает первый элемент списка, удовлетворяющий предикату. Правда, тип у неё несколько необычный:
>ghci> :t find
>find :: (a -> Bool) -> [a] -> Maybe a
Первый параметр – предикат, второй – список, с этим всё ясно. Но что с возвращаемым значением? Что это за >Maybe a
? Это тип, который нам до сих пор не встречался. Значение с типом >Maybe a
немного похоже на список типа >[a]
. Если список может иметь ноль, один или много элементов, то значение типа >Maybe a
может иметь либо ноль элементов, либо в точности один. Эту штуку можно использовать, если мы хотим предусмотреть возможность провала. Значение, которое ничего не содержит, – >Nothing
. Оно аналогично пустому списку. Для конструирования значения, которое что-то содержит, скажем, строку >"эй"
, будем писать >Just "эй"
. Вот как всё это выглядит:
>ghci> Nothing
>Nothing
>ghci> Just "эй"
>Just "эй"
>ghci> Just 3
>Just 3
>ghci> :t Just "эй"
>Just "эй" :: Maybe [Char]
>ghci> :t Just True
>Just True :: Maybe Bool
Видите, значение >Just True
имеет тип >Maybe Bool
. Похоже на то, что список, содержащий значения типа >Bool
, имеет тип >[Bool]
.
Если функция >find
находит элемент, удовлетворяющий предикату, она возвращает этот элемент, обёрнутый в >Just
. Если не находит, возвращает >Nothing
:
>ghci> find (>4) [3,4,5,6,7]
>Just 5
>ghci> find odd [2,4,6,8,9]
>Just 9
>ghci> find (=='x') "меч-кладенец"
>Nothing
Вернёмся теперь к нашей задаче. Мы уже написали функцию >digitSum
и знаем, как она работает, так что пришла пора собрать всё вместе. Напомню, что мы хотим найти число, сумма цифр которого равна 40.
>firstTo40 :: Maybe Int
>firstTo40 = find (\x -> digitSum == 40) [1..]
Мы просто взяли бесконечный список >[1..]
и начали искать первое число, значение >digitSum
для которого равно 40.
>ghci> firstTo40
>Just 49999
А вот и ответ! Можно сделать более общую функцию, которой нужно передавать искомую сумму в качестве параметра: