ПРИМЕЧАНИЕ.
Чтобы создать список со всеми числами от 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]