Учебник по Haskell | страница 60



уравнении нам встретится узел дерева, который содержит конструктор :, а в дочерних узлах сидят элемент

списка a и оставшаяся часть списка as. В этом случае мы составляем новый список, элемент которого со-

держит преобразованный элемент (f a) исходного списка и оставшуюся часть списка, которую мы также

преобразуем с помощью функции map:

map :: (a -> b) -> [a] -> [b]

map f []

= []

map f (a:as) = f a : map f as

Какое длинное объяснение для такой короткой функции! Надеюсь, что мне не удалось сбить вас с толку.

Обратите внимание на то, что поскольку конструктор символьный (начинается с двоеточия) мы пишем его

между дочерними поддеревьями, а не сначала. Немного отвлекитесь и поэкспериментируйте с этой функци-

ей в интерпретаторе, она очень важная. Составляйте самые разные списки. Чтобы не перенабирать каждый

раз списки водите синонимы с помощью let.

Перейдём к следующей функции. Это функция фильтрации:

filter :: (a -> Bool) -> [a] -> [a]

Она принимает предикат и список, угдайте что она делает:

Prelude Data.Char> filter isUpper ”Hello World”

”HW”

Prelude Data.Char> filter even [1,2,3,4,5]

[2,4]

Prelude Data.Char> filter (> 10) [1,2,3,4,5]

[]

Да, она оставляет лишь те элементы, на которых предикат вернёт истину. Потренируйтесь и с этой функ-

цией.

Теперь определение:

filter :: (a -> Bool) -> [a] -> [a]

filter p []

= []

filter p (x:xs) = if p x then x : filter p xs else filter p xs

Попробуйте разобраться с ним самостоятельно, по аналогии с map. Оно может показаться немного гро-

моздким, но это ничего, совсем скоро мы узнаем как записать его гораздо проще.

Рассмотрим ещё одну функцию для списков, она называется функцией свёртки:

Рекурсивные типы | 55

foldr :: (a -> b -> b) -> b -> [a] -> b

foldr f z []

= z

foldr f z (a:as) = f a (foldr f z as)

Визуально её действие можно представить как замену всех конструкторов в дереве значения на подхо-

дящие по типу функции. В этой маленькой функции кроется невероятная сила. Посмотрим на несколько

примеров:

Prelude Data.Char> :m -Data.Char

Prelude> let xs = [1,2,3,4,5]

Prelude> foldr (:) [] xs

[1,2,3,4,5]

Мы заменили конструкторы на самих себя и получили исходный список, теперь давайте сделаем что-

нибудь более конструктивное. Например вычислим сумму всех элементов или произведение:

Prelude> foldr (+) 0 xs

15

Prelude> foldr (*) 1 xs

120

Prelude> foldr max (head xs) xs

5

3.6 Краткое содержание

В этой главе мы присмотрелись к типам и узнали как ограничения, общие для всех типов, сказываются