ПРИМЕЧАНИЕ. Чтобы создать список со всеми числами от 20 до 1 по убыванию, вы не можете просто написать [20..1]
, а должны написать [20,19..1]
. При попытке записать такой интервал без шага (т. е. [20..1]
) Haskell начнёт с пустого списка, а затем будет увеличивать начальный элемент на единицу, пока не достигнет или не превзойдёт элемент в конце интервала. Поскольку 20 уже превосходит 1, результат окажется просто пустым списком.
Будьте осторожны при использовании чисел с плавающей точкой в интервалах! Из-за того что они не совсем точны (по определению), их использование в диапазонах может привести к весьма забавным результатам.
ghci> [0.1, 0.3 .. 1]
[0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]
Мой совет:
Интервалы, кроме прочего, можно использовать для создания бесконечных списков, просто не указывая верхний предел. Позже мы рассмотрим этот вариант в подробностях. А сейчас давайте посмотрим, как можно получить список первых 24 чисел, кратных 13. Конечно, вы могли бы написать [13,26..24*13]
. Но есть способ получше: take 24 [13,26..]
. Поскольку язык Haskell ленив, он не будет пытаться немедленно вычислить бесконечный список, потому что процесс никогда не завершится. Он подождёт, пока вы не захотите получить что-либо из такого списка. Тут-то обнаружится, что вы хотите получить только первые 24 элемента, что и будет исполнено.
Немного функций, производящих бесконечные списки:
• Функция cycle
принимает список и зацикливает его в бесконечный. Если вы попробуете отобразить результат, на это уйдёт целая вечность, поэтому вам придётся где-то его обрезать.
ghci> take 10 (cycle [1,2,3])
[1,2,3,1,2,3,1,2,3,1]
ghci> take 12 (cycle "LOL ")
"LOL LOL LOL "
• Функция repeat
принимает элемент и возвращает бесконечный список, состоящий только из этого элемента. Это подобно тому, как если бы вы зациклили список из одного элемента.
ghci> take 10 (repeat 5)
[5,5,5,5,5,5,5,5,5,5]
Однако проще использовать функцию replicate
, если вам нужен список из некоторого количества одинаковых элементов. replicate 3 10
вернёт [10,10,10]
.
Генераторы списков
Если вы изучали курс математики, то, возможно, сталкивались со способом задания множества путём описания характерных свойств, которыми должны обладать его элементы. Обычно этот метод используется для построения подмножеств из множеств.
Вот пример простого описания множества. Множество, состоящее из первых десяти чётных чисел, это S = {2 ·
Если бы нам потребовалось написать то же самое на языке 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]
, умножаются на два.
Теперь давайте добавим к этому генератору условие выборки (
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]