Последовательности

Clojure определяет многие алгоритмы в терминах последовательностей (seq). Seq - это логический список, и в отличие от большинства лисперов, где список представлен конкретной двухслотовой структурой, Clojure использует интерфейс ISeq, позволяющий многим структурам данных предоставлять доступ к своим элементам в виде последовательностей. Функция seq выдает реализацию ISeq, соответствующую коллекции. Последовательности отличаются от итераторов тем, что они являются постоянными и неизменяемыми, а не курсорами состояния коллекции. Как таковые, они полезны для гораздо большего, чем foreach - функции могут потреблять и производить seq, они потокобезопасны, могут разделять структуру и т.д.

Большинство функций библиотеки последовательностей являются ленивыми, т.е. функции, возвращающие seq, делают это постепенно, по мере их потребления, и, таким образом, потребляют любые аргументы seqs также постепенно. Функции, возвращающие ленивые seq, могут быть реализованы с помощью макроса lazy-seq. См. также lazy.

Когда seq используется для объектов, реализующих Iterable, результирующая последовательность остается неизменяемой и постоянной, и будет представлять собой один проход по данным. Поскольку этот проход может происходить лениво, он может увидеть изменения, произошедшие после вызова seq. Кроме того, если подкрепляющий итератор подвержен ConcurrentModificationException, то и результирующий seq тоже. Когда seq используется с массивами Java, изменения в базовом массиве будут отражены в seq - для получения полной неизменяемости необходимо скопировать исходный массив. Тем не менее, использование seq для итерабельных массивов и массивов по-прежнему очень полезно, поскольку seq поддерживают многопроходные и ленивые алгоритмы. Надежные программы не должны мутировать массивы или Iterables, на которых есть seq.

Многие функции библиотеки seq берут одну или несколько коллекций, вызывают для них seq, а затем работают с полученным seq. Другими словами, многие из этих функций берут коллекции, но работают с их секвенциями.

Интерфейс Seq

(_first_ coll)

Возвращает первый элемент в коллекции. Вызывает функцию seq на своем аргументе. Если coll равен nil, возвращает nil.

(_rest_ coll)

Возвращает последовательность элементов после первого. Вызывает seq на своем аргументе. Если элементов больше нет, возвращает логическую последовательность, для которой seq возвращает nil.

(_cons_ item seq)

Возвращает новый seq, где item - первый элемент, а seq - остальные.

Для обсуждения rest против next и lazy-seq смотрите lazy.

Библиотека Seq

Это выборка основных функций последовательности, сгруппированных по их возможностям. Некоторые функции могут использоваться по-разному и поэтому представлены в нескольких группах. Многие другие перечислены в разделе API.

Начиная с версии Clojure 1.7, Clojure также предоставляет трансдьюсеры, альтернативную модель для композиционных преобразований коллекций. Трансдьюсеры разделяют входную, обрабатывающую и выходную части преобразования и позволяют повторно использовать преобразования в большем количестве контекстов, например, в каналах core.async. Многие функции последовательности из приведенного ниже списка создают трансдьюсеры, если входная коллекция опущена. Более подробную информацию см. на странице трансдьюсеры.

Seq in, Seq out

Более короткий seq из более длинного seq: distinct filter remove for keep keep-indexed
Более длинный seq из более короткого seq: cons concat lazy-cat mapcat cycle interleave interpose
Секвенция с отсутствующими головными элементами: rest next fnext nnext drop drop-while nthnext for
Секвенция с отсутствующими хвостовыми элементами: take take-nth take-while butlast drop-last for
Перестановка последовательности: flatten reverse sort sort-by shuffle
Создание вложенных секвенций: split-at split-with partition partition-all partition-by
Обработка каждого элемента seq для создания нового seq: map pmap mapcat for replace reductions map-indexed seque

Использование последовательности

Извлечение элемента с определенным номером из последовательности: first ffirst nfirst second nth when-first last rand-nth
Создайте коллекцию из seq: zipmap into reduce set vec into-array to-array-2d frequencies group-by
Передать элементы последовательности в качестве аргументов функции: apply
Вычислить логическое число из seq: not-empty some reduce seq? every? not-every? not-any? empty?
Поиск последовательности с использованием предиката: some filter
Принудительная оценка ленивых секвенций: doseq dorun doall
Проверить, были ли ленивые секвенции принудительно вычислены до конца: realized?

Создание последовательности

Ленивый seq из коллекции: seq vals keys rseq subseq rsubseq
Ленивый seq из функции: lazy-seq repeatedly iterate
Ленивый запрос от константы: repeat range
Ленивое выделение из других объектов: line-seq resultset-seq re-seq tree-seq file-seq xml-seq iterator-seq enumeration-seq
)