Изучай Haskell во имя добра! (Липовача) - страница 72

из модуля >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

А вот и ответ! Можно сделать более общую функцию, которой нужно передавать искомую сумму в качестве параметра: