Ответ 1
Одно отличие состоит в том, что conj
принимает любое количество аргументов для вставки в коллекцию, а 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
, поэтому a count
на нем больше не является операцией с постоянным временем (в этом случае оно, вероятно, уменьшится до 1 + 3 - 1 происходит от линейного обхода по первому элемент, 3 получается из (next (cons 4 '(1 2 3))
, являющегося PersistentList
и, следовательно, Counted
).
Предполагает, что cons
означает, что cons
означает cons (tect a seq) 1 тогда как conj
означает соединить (элемент с элементом в коллекцию). Конструкция seq
, созданная cons
, начинается с элемента, переданного в качестве первого аргумента, и имеет в качестве своей части next
/rest
вещь, полученную в результате применения seq
ко второму аргументу; как показано выше, все дело в классе clojure.lang.Cons
. Напротив, conj
всегда возвращает коллекцию примерно того же типа, что и переданная ей коллекция. (Грубо, потому что a PersistentArrayMap
будет превращен в PersistentHashMap
, как только он вырастет выше 9 записей.)
1 Традиционно в мире Lisp cons
cons (создает пару), поэтому Clojure отходит от традиции Lisp, имея конструкцию cons
seq, который не имеет традиционного cdr
. Обобщенное использование cons
, означающее "построить запись того или иного типа для хранения целого ряда значений", в настоящее время является повсеместным в изучении языков программирования и их реализации; что означало, когда упоминается "избегание consing".