×
Traktatov.net » Изучай Haskell во имя добра! » Читать онлайн
Страница 13 из 245 Настройки

Если бы нам потребовалось написать то же самое на языке Haskell, можно было бы изобрести что-то вроде: >take 10 [2,4..]. Но что если мы хотим не просто получить первые десять удвоенных натуральных чисел, а применить к ним некую более сложную функцию? Для этого можно использовать генератор списков. Он очень похож на описание множеств:

>ghci> [x*2 | x <– [1..10]]

>[2,4,6,8,10,12,14,16,18,20]

В выражении >[x*2 | x <– [1..10]] мы извлекаем элементы из списка >[1..10], т. е. >x последовательно принимает все значения элементов списка. Иногда говорят, что >xсвязывается с каждым элементом списка. Часть генератора, находящаяся левее вертикальной черты >|, определяет значения элементов результирующего списка. В нашем примере значения >x, извлечённые из списка >[1..10], умножаются на два.

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

>ghci> [x*2 | x <– [1..10], x*2 >= 12]

>[12,14,16,18,20]

Это работает. Замечательно! А как насчёт ситуации, когда требуется получить все числа от 50 до 100, остаток от деления на 7 которых равен 3? Легко!

>ghci> [ x | x <– [50..100], x `mod` 7 == 3]

>[52,59,66,73,80,87,94]

И снова получилось!

ПРИМЕЧАНИЕ. Заметим, что прореживание списков с помощью условий выборки также называется фильтрацией.

Мы взяли список чисел и отфильтровали их условиями. Теперь другой пример. Давайте предположим, что нам нужно выражение, которое заменяет каждое нечётное число больше 10 на >БАХ!", а каждое нечётное число меньше 10 – на >БУМ!". Если число чётное, мы выбрасываем его из нашего списка. Для удобства поместим выражение в функцию, чтобы потом легко использовать его повторно.

>boomBangs xs = [if x < 10 then "БУМ!" else "БАХ!" | x <– xs, odd x]

ПРИМЕЧАНИЕ. Помните, что если вы пытаетесь определить эту функцию в GHCi, то перед её именем нужно написать >let. Если же вы описываете её в отдельном файле, а потом загружаете его в GHCi, то никакого >let не требуется.

Последняя часть описания – условие выборки. Функция >odd возвращает значение >True для нечётных чисел и >False – для чётных. Элемент включается в список, только если все условия выборки возвращают значение >True.

>ghci> boomBangs [7..13]

>["БУМ!","БУМ!","БАХ!","БАХ!"]

Мы можем использовать несколько условий выборки. Если бы по требовалось получить все числа от 10 до 20, кроме 13, 15 и 19, то мы бы написали:

>ghci> [x | x <– [10..20], x /= 13, x /= 15, x /= 19]

>[10,11,12,14,16,17,18,20]

Можно не только написать несколько условий выборки в генераторах списков (элемент должен удовлетворять всем условиям, чтобы быть включённым в результирующий список), но и выбирать элементы из нескольких списков. В таком случае выражения перебирают все комбинации из данных списков и затем объединяют их по производящей функции, которую мы указали:

>ghci> [x+y | x <- [1,2,3], y <- [10,100,1000]]

>[11,101,1001,12,102,1002,13,103,1003]

Здесь >x берётся из списка >[1,2,3], а >y – из списка