Clojure

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

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

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

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

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

Интерфейс Seq

(first coll)

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

(rest coll)

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

(cons item seq)

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

Сравнение rest, next и lazy-seq см. разделе леность

Библиотека последовательностей

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

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

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

Более короткая последовательность из более длинной: distinct filter remove for keep keep-indexed
Более длинная последовательность из более короткой: 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
Обработка каждого элемента последовательности для создания новой: map pmap mapcat for replace reductions map-indexed seque

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

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

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

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