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