Я программист на Java и новичок в Clojure. Из разных мест я видел, как последовательность и коллекция используются в разных случаях. Тем не менее, я понятия не имею, какова точная разница между ними.
Как вы можете видеть, при описании интерфейса Seq первые две функции (first/rest) используют coll
что указывает на то, что это коллекция, а функция cons
использует seq
которая указывает на то, что это последовательность.
Я думаю, что это довольно простой вопрос для Clojure, но я не могу найти место, объясняющее это ясно, в чем их различие и какой из них мне следует использовать в разных случаях. Любой комментарий приветствуется.
Ответ 2
Любой объект, поддерживающий основные функции first
и rest
, является sequence
.
Многие объекты удовлетворяют этому интерфейсу, и каждая коллекция Clojure предоставляет по крайней мере один вид seq-объекта для перехода через его содержимое с помощью функции seq
.
Итак:
user> (seq [1 2 3])
(1 2 3)
И вы можете создать объект последовательности из map
тоже
user> (seq {:a 1 :b 2})
([:a 1] [:b 2])
Для этого вы можете использовать filter
, map
, for
и т.д. на maps
sets
и т.д.
Таким образом, вы можете обрабатывать многие объекты, подобные коллекциям, в виде последовательностей.
Вот почему многие функции обработки последовательности, такие как filter
вызывают seq
на входе:
(defn filter
"Returns a lazy sequence of the items in coll for which
(pred item) returns true. pred must be free of side-effects."
{:added "1.0"
:static true}
([pred coll]
(lazy-seq
(when-let [s (seq coll)]
Если вы вызываете (filter pred 5)
Don't know how to create ISeq from: java.lang.Long
RT.java:505 clojure.lang.RT.seqFrom
RT.java:486 clojure.lang.RT.seq
core.clj:133 clojure.core/seq
core.clj:2523 clojure.core/filter[fn]
Вы видите, что вызов seq
- это объект проверки последовательности.
Большая часть этого материала находится в Радость Clojure главы 5, если вы хотите углубиться.
Ответ 6
Я только что прочитал главу 5 - "Типы коллекций" "Радости Clojure", которая немного сбивает с толку (то есть следующая версия этой книги нуждается в рецензировании). В главе 5 на странице 86 есть таблица, которой я не полностью доволен:
![Table 5.1 from the Joy of Clojure, 2nd ed.]()
Итак, вот мое мнение (полностью обновлено после возвращения к этому после месяца размышлений).
коллекция
Это "вещь", коллекция других вещей.
Это основано на функции coll?
.
- Функция
coll?
может использоваться для проверки этого.
- И наоборот, все, для чего
coll?
возвращает true, является коллекцией.
Строка документации coll?
гласит:
Возвращает true, если x реализует IPersistentCollection
Вещи, которые являются коллекциями, сгруппированными в три отдельных класса. Вещи в разных классах никогда не равны.
- Тест карт с использованием
(map? foo)
- Карта (две фактические реализации с немного отличающимся поведением)
- Сортированная карта. Примечание:
(sequential? (sorted-map :a 1)
; => false
- Устанавливает тест с использованием
(set? foo)
- Установить
- Сортированный набор. Примечание:
(sequential? (sorted-set :a :b))
; => false
- Тест последовательных коллекций с использованием
(sequential? foo)
- Список
- Вектор
- Очередь
- Seq:
(sequential? (seq [1 2 3]))
; => true
- Lazy-Seq:
(sequential? (lazy-seq (seq [1 2 3])))
; => true
Взаимодействие с Java за пределами этого:
(coll? (to-array [1 2 3]))
; => false
(map? (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2)))
; => false
последовательный сбор ("цепочка")
Это "вещь", коллекция, содержащая другие вещи в соответствии с определенным, стабильным порядком.
Это основано на функции sequential?
.
- Функция
sequential?
может использоваться для проверки этого.
- И наоборот, все, для чего
sequential?
возвращает true, является последовательной коллекцией.
Строка документации sequential?
гласит:
Возвращает true, если coll реализует Sequential
Примечание: "последовательный" является прилагательным! В "Радости Clojure" прилагательное используется как существительное, и это очень, очень, очень запутанно:
"Clojure классифицирует каждый тип данных коллекции на один из трех логические категории или разделы: последовательности, карты и наборы. "
Вместо "последовательной" следует использовать "последовательную вещь" или "последовательную коллекцию" (как использовано выше). С другой стороны, в математике уже существуют следующие слова: "цепочка", "полностью упорядоченное множество", "просто упорядоченное множество", "линейно упорядоченное множество". "цепь" звучит отлично, но никто не использует это слово. Позор!
"Радость Clojure" также говорит следующее:
Beware type-based predicates!
Clojure включает несколько предикатов с именами, такими как слова просто определены. Хотя они не часто используются, кажется, стоит упоминая, что они могут не иметь в виду именно то, что определения здесь может предложить. Например, каждый объект для которого последовательный? возвращается true - это последовательная коллекция, но для некоторых она возвращает false также последовательны [лучше: "это можно считать последовательным Коллекции "]. Это из-за деталей реализации, которые могут быть улучшена в будущей версии Clojure [и, возможно, это уже было сделано?]
последовательность (также "абстракция последовательности")
Это скорее концепция, чем вещь: серия значений (упорядоченных таким образом), которые могут существовать или не существовать (то есть поток). Если вы говорите, что вещь - это последовательность, является ли эта вещь обязательно коллекцией Clojure, даже последовательной коллекцией? Я так полагаю.
Эта последовательная коллекция может быть полностью вычислена и быть полностью доступной. Или это может быть "машина" для генерации значений по необходимости (путем вычислений - вероятно, "чистым" способом - или путем запроса внешних "нечистых", "оракулярных" источников: клавиатура, базы данных)
сл
Это вещь: то, что может быть обработано функциями
first
, rest
, next
, cons
(и, возможно, другие?), То есть что-то, что подчиняется протоколу protocol clojure.lang.ISeq
(что примерно соответствует концепции "обеспечения реализации для интерфейс "в Java), то есть система зарегистрировала реализации функций для пары (вещь, имя-функции) [Я очень надеюсь, что я понимаю это правильно...]
Это основано на функции seq?
.
- Функция
seq?
может использоваться для проверки этого
- И наоборот, seq - это все, для чего
seq?
возвращает true.
Строка документации для seq?
:
Вернуть true, если x реализует ISeq
Строка документации для first
:
Возвращает первый элемент в коллекции. Вызывает seq на свой аргумент. Если coll - ноль, возвращает ноль.
Строка документации для rest
:
Возвращает возможно пустую последовательность элементов после первого. Вызовы seq на его аргумент.
Строка документации для next
:
Возвращает последовательность пунктов после первого. Вызывает seq на свой аргумент. Если товаров больше нет, возвращается ноль.
Вы вызываете next
в seq для генерации следующего элемента и нового seq. Повторяйте до тех пор, пока nil
не будет получено.
Радость Clojure называет это "простым API для навигации по коллекциям" и говорит, что "seq - это любой объект, который реализует API seq" - что правильно, если "API" является ансамблем "вещи" (определенного типа). и функции, которые работают на эту вещь. Это зависит от подходящего сдвига в концепции API.
Примечание по особому случаю пустой последовательности:
(def empty-seq (rest (seq [:x])))
(type? empty-seq) ;=> clojure.lang.PersistentList$EmptyList
(nil? empty-seq) ;=> false ... empty seq is not nil
(some? empty-seq) ;=> true ("true if x is not nil, false otherwise.")
(first empty-seq) ;=> nil ... first of empty seq is nil ("does not exist"); beware confusing this with a nil in a nonempty list!
(next empty-seq) ;=> nil ... "next" of empty seq is nil
(rest empty-seq) ;=> () ... "rest" of empty seq is the empty seq
(type (rest empty-seq)) ;=> clojure.lang.PersistentList$EmptyList
(seq? (rest empty-seq)) ;=> true
(= (rest empty-seq) empty-seq) ;=> true
(count empty-seq) ;=> 0
(empty? empty-seq) ;=> true
Addenda
Функция seq
Если вы примените функцию seq
к тому, для чего это имеет смысл (обычно это последовательная коллекция), вы получите последовательность, представляющую/генерирующую элементы этой коллекции.
Строка документа говорит:
Возвращает последовательность в коллекции. Если коллекция пуста, возвращает ноль. (seq nil) возвращает ноль. seq также работает на Strings, родной Java массивы (ссылочных типов) и любые объекты, которые реализуют Iterable. Обратите внимание, что значения кэша seqs, таким образом, seq не должен использоваться ни на каких Итерируемый, итератор которого многократно возвращает один и тот же изменяемый объект.
После применения seq
вы можете получить объекты различных реальных классов:
clojure.lang.Cons
- попробуйте (class (seq (map #(* % 2) '( 1 2 3))))
clojure.lang.PersistentList
clojure.lang.APersistentMap$KeySeq
clojure.lang.PersistentList$EmptyList
clojure.lang.PersistentHashMap$NodeSeq
clojure.lang.PersistentQueue$Seq
clojure.lang.PersistentVector$ChunkedSeq
Если вы примените seq
к последовательности, фактический класс возвращаемой вещи может отличаться от фактического класса передаваемой вещи. Это все равно будет последовательность.
Каковы "элементы" в последовательности, зависит. Например, для карт они представляют собой пары ключ-значение, которые выглядят как 2-элементные vector
(но их фактический класс не является вектором).
Функция lazy-seq
Создает объект для ленивого создания большего количества объектов (приостановленный компьютер, приостановленный поток, thunk)
Строка документа говорит:
Принимает тело выражений, которое возвращает ISeq или nil, и возвращает Seqable объект, который будет вызывать тело только в первый раз, когда seq вызывается, и кеширует результат и возвращает его на всех последующих звонки. Смотрите также - поняли? "
Заметка о "функциях" и "вещах"... и "объектах"
В Clojure Universe мне нравится говорить о "функциях" и "вещах", но не об "объектах", что является термином, сильно нагруженным Java-ностью и прочими недостатками. Упоминание об объектах похоже на осколки, исходящие из базовой вселенной Java.
В чем разница между функцией и вещью?
Это жидкость! Некоторые вещи - это чистые функции, некоторые вещи - чистые вещи, некоторые между ними (могут использоваться как функции и имеют атрибуты вещей)
В частности, Clojure допускает контексты, в которых ключевые слова (вещи) рассматриваются как функции (для поиска значений в картах) или когда интерпретируются карты (вещи) как функции, или сокращение для функций (которые берут ключ и возвращают значение, связанное с этим. введите карту)
Очевидно, что функции - это вещи, поскольку они являются "первоклассными гражданами".
Это также контекстно! В некоторых случаях функция становится вещью, или вещь становится функцией.
Есть неприятные упоминания об объектах... это осколки, выскакивающие из базовой вселенной Java.
В целях презентации, схема коллекций
![Collections in Clojure]()