Clojure: недостатки (seq) по сравнению с союзом (список)

Я знаю это cons возвращает seq и conj возвращает набор. Я также знаю это conj "добавляет" объект к оптимальному концу набора, и cons всегда "добавляет" объект к передней стороне. Этот пример иллюстрирует оба из этих тезисов:

user=> (conj [1 2 3] 4) //returns a collection
[1 2 3 4]
user=> (cons 4 [1 2 3]) //returns a seq
(4 1 2 3)

Для векторов, карт и наборов эти различия имеют смысл мне. Однако для списков они кажутся идентичными.

user=> (conj (list 3 2 1) 4) //returns a list
(4 3 2 1)
user=> (cons 4 (list 3 2 1)) //returns a seq
(4 3 2 1)

Есть ли любые примеры с помощью списков где conj по сравнению с. cons покажите различные поведения, или действительно ли они являются действительно взаимозаменяемыми? Формулируемый по-другому, там пример, где список и seq не могут использоваться эквивалентно?

96
задан albusshin 15 March 2014 в 09:50
поделиться

3 ответа

Одно отличие состоит в том, что con принимает любое количество аргументов для вставки в коллекцию, тогда как cons принимает только один:

(conj '(1 2 3) 4 5 6)
; => (6 5 4 1 2 3)

(cons 4 5 6 '(1 2 3))
; => IllegalArgumentException due to wrong arity

Другое отличие заключается в классе возвращаемого значения :

(class (conj '(1 2 3) 4))
; => clojure.lang.PersistentList

(class (cons 4 '(1 2 3))
; => clojure.lang.Cons

Обратите внимание, что на самом деле они не взаимозаменяемы; в частности, clojure.lang.Cons не реализует clojure.lang.Counted , поэтому счет на нем больше не является операцией с постоянным временем (в этом случай, вероятно, уменьшится до 1 + 3 - 1 происходит от линейного обхода первого элемента, 3 происходит от (next (cons 4 '(1 2 3)) является PersistentList и, таким образом, Подсчитано ).

Я считаю, что за названиями стоит cons означает cons (truct a seq) 1 , тогда как con означает объединение элемента в коллекцию. seq , создаваемый cons , начинается с элемента, переданного в качестве его первого аргумента, и имеет поскольку его next / rest часть того, что является результатом применения seq ко второму аргументу; как показано выше, все это относится к классу clojure.lang.Cons . I В отличие от этого, con всегда возвращает коллекцию примерно того же типа, что и переданная ей коллекция. (Грубо говоря, потому что PersistentArrayMap будет преобразован в PersistentHashMap , как только он превысит 9 записей.)


1 Традиционно в мире Lisp cons cons (исправляет пару), поэтому Clojure отходит от традиции Lisp в том, что его функция cons создает последовательность у которого нет традиционного cdr . Обобщенное использование cons для обозначения «создания записи того или иного типа для хранения нескольких значений вместе» в настоящее время повсеместно используется при изучении языков программирования и их реализации; это то, что имеется в виду, когда упоминается «избегание совершения».

146
ответ дан 24 November 2019 в 05:39
поделиться

Насколько я понимаю, то, что вы говорите, правда: cons в списке эквивалентно cons в списке.

Вы можете думать о конъюнктуре как об операции «вставить куда-нибудь», а о cons как о операции «вставить в начало». В списке логичнее всего вставлять в начале, поэтому в этом случае "минусы" и "минусы" эквивалентны.

10
ответ дан 24 November 2019 в 05:39
поделиться

Еще одно отличие состоит в том, что, поскольку conj принимает последовательность в качестве первого аргумента, она хорошо сочетается с alter при обновлении ref. ] в некоторую последовательность:

(dosync (alter a-sequence-ref conj an-item))

Это в основном делает (conj a-sequence-ref an-item) потокобезопасным способом. Это не будет работать с cons. Дополнительную информацию см. в главе о параллелизме в книге Programming Clojure Стью Хэллоуэя.

8
ответ дан 24 November 2019 в 05:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: