Выбрать главу

[1,2,3,4,5]

Написать [1,2,3,4] ++ 5 нельзя, потому что оба параметра оператора ++ должны быть списками, а 5 – это не список, а число.

Интересно, что [1,2,3] – это на самом деле синтаксический вариант 1:2:3:[]. Список [] – пустой, и если мы добавим к его началу 3, получится [3]; если затем добавим в начало 2, получится [2,3] и т. д.

ПРИМЕЧАНИЕ. Списки [], [[]] и [[],[],[]] совершенно разные. Первый – это пустой список; второй – список, содержащий пустой список; третий – список, содержащий три пустых списка.

Обращение к элементам списка

Если вы хотите извлечь элемент из списка по индексу, используйте оператор !!. Индексы начинаются с нуля.

ghci> "Стив Бушеми" !! 5

'Б'

ghci> [9.4,33.2,96.2,11.2,23.25] !! 1

33.2

Но если вы попытаетесь получить шестой элемент списка, состоящего из четырёх элементов, то получите сообщение об ошибке, так что будьте осторожны!

Списки списков

Списки могут содержать другие списки. Также они могут содержать списки, которые содержат списки, которые содержат списки…

ghci> let b = [[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]

ghci> b

[[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]

ghci> b ++ [[1,1,1,1]]

[[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3],[1,1,1,1]]

ghci> [6,6,6]:b

[[6,6,6],[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]

ghci> b !! 2

[1,2,2,3,4]

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

Сравнение списков

Списки можно сравнивать, только если они содержат сравнимые элементы. При использовании операторов <, <=, >= и > сравнение происходит в лексикографическом порядке. Сначала сравниваются «головы» списков; если они равны, то сравниваются вторые элементы. Если равны и вторые элементы, то сравниваются третьи – и т. д., пока не будут найдены различающиеся элементы. Результат сравнения списков определяется по результату сравнения первой пары различающихся элементов.

Сравним для примера [3,4,2]<[3,4,3]. Haskell видит, что 3 и 3 равны, поэтому переходит к сравнению 4 и 4, но так как они тоже равны, сравнивает 2 и 3. Число 2 меньше 3, поэтому первый список меньше второго. Аналогично выполняется сравнение на <=, >= и >:

ghci> [3,2,1] > [2,1,0]

True

ghci> [3,2,1] > [2,10,100]

True

ghci> [3,4,2] < [3,4,3]

True

ghci> [3,4,2] > [2,4]

True

ghci> [3,4,2] == [3,4,2]

True

Непустой список всегда считается больше, чем пустой. Это позволяет сравнивать друг с другом любые два списка, даже если один из них точно совпадает с началом другого.

Другие операции над списками

Что ещё можно делать со списками? Вот несколько основных функций работы с ними.

Функция head принимает список и возвращает его головной элемент. Головной элемент списка – это, собственно, его первый элемент.

ghci> head [5,4,3,2,1]

5

Функция tail принимает список и возвращает его «хвост». Иными словами, эта функция отрезает «голову» списка и возвращает остаток.

ghci> tail [5,4,3,2,1]

[4,3,2,1]

Функция last принимает список и возвращает его последний элемент.

ghci> last [5,4,3,2,1]

1

Функция init принимает список и возвращает всё, кроме его последнего элемента.

ghci> init [5,4,3,2,1]

[5,4,3,2]

Если представить список в виде сороконожки, то с функциями получится примерно такая картина:

Но что будет, если мы попытаемся получить головной элемент пустого списка?

ghci> head []

*** Exception: Prelude.head: empty list

Ну и ну! Всё сломалось!.. Если нет сороконожки, нет и «головы». При использовании функций head, tail, last и init будьте осторожны – не применяйте их в отношении пустых списков. Эту ошибку нельзя отловить на этапе компиляции, так что всегда полезно предотвратить случайные попытки попросить язык Haskell выдать несколько элементов из пустого списка.

Функция length, очевидно, принимает список и возвращает его длину: