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