Я знаю это 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 не могут использоваться эквивалентно?
Одно отличие состоит в том, что 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
для обозначения «создания записи того или иного типа для хранения нескольких значений вместе» в настоящее время повсеместно используется при изучении языков программирования и их реализации; это то, что имеется в виду, когда упоминается «избегание совершения».
Насколько я понимаю, то, что вы говорите, правда: cons в списке эквивалентно cons в списке.
Вы можете думать о конъюнктуре как об операции «вставить куда-нибудь», а о cons как о операции «вставить в начало». В списке логичнее всего вставлять в начале, поэтому в этом случае "минусы" и "минусы" эквивалентны.
Еще одно отличие состоит в том, что, поскольку conj
принимает последовательность в качестве первого аргумента, она хорошо сочетается с alter
при обновлении ref
. ] в некоторую последовательность:
(dosync (alter a-sequence-ref conj an-item))
Это в основном делает (conj a-sequence-ref an-item)
потокобезопасным способом. Это не будет работать с cons
. Дополнительную информацию см. в главе о параллелизме в книге Programming Clojure Стью Хэллоуэя.