Примеры свёрток

We use cookies. Read the Privacy and Cookie Policy

Для того чтобы показать, насколько мощны свёртки, мы собираемся реализовать с их помощью несколько стандартных библиотечных функций. Во-первых, реализуем свою версию функции reverse:

reverse' :: [a] -> [a]

reverse' = foldl (acc x -> x : acc) []

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

Функция acc x -> x : acc – почти то же, что и операция :, за исключением порядка следования параметров. Поэтому функцию reverse' можно переписать и так:

reverse' :: [a] -> [a]

reverse' = foldl (flip (:)) []

Теперь реализуем функцию product:

product' :: (Num a) => [a] -> a

product' = foldl (*) 1

Чтобы вычислить произведение всех элементов списка, следует начать с аккумулятора равного 1. Затем мы выполняем свёртку функцией (*), которая перемножает каждый элемент списка на аккумулятор.

Вот реализация функции filter:

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

filter' p = foldr (x acc -> if p x then x : acc else acc) []

Здесь начальное значение аккумулятора является пустым списком. Мы сворачиваем список справа налево и проверяем каждый элемент, пользуясь предикатом p. Если p x возвращает истину, элемент x помещается в начало аккумулятора. В противном случае аккумулятор остаётся без изменения.

Напоследок реализуем функцию last:

last' :: [a] -> a

last' = foldl1 ( x -> x)

Для получения последнего элемента списка мы применяем foldr1. Начинаем с «головы» списка, а затем применяем бинарную функцию, которая игнорирует аккумулятор и устанавливает текущий элемент списка как новое значение аккумулятора. Как только мы достигаем конца списка, аккумулятор — то есть последний элемент – возвращается в качестве результата свёртки.