Jedna różnica polega na tym, że conj
akceptuje dowolną liczbę argumentów do wstawienia do kolekcji, podczas gdy cons
zajmuje tylko jeden:
(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
Kolejna różnica dotyczy klasy wartości zwracanej:
(class (conj '(1 2 3) 4))
; => clojure.lang.PersistentList
(class (cons 4 '(1 2 3))
; => clojure.lang.Cons
Zauważ, że nie są one w rzeczywistości zamienne; w szczególności clojure.lang.Cons
nie implementuje clojure.lang.Counted
, więc a count
on nie jest już operacją o stałym czasie (w tym przypadku prawdopodobnie zmniejszyłaby się do 1 + 3 - 1 pochodzi z liniowego przechodzenia po pierwszym elemencie, 3 pochodzi z (next (cons 4 '(1 2 3))
bycia a PersistentList
i w ten sposób Counted
).
Uważam, że intencją kryjącą się za nazwami jest cons
cons (truct a seq) 1 , podczas gdy conj
oznacza połączenie (łączenie pozycji z kolekcją). seq
Skonstruowany przez cons
rozpoczęciem z elementem przekazanym jako pierwszy argument i ma na next
/ rest
części Rzecz wynikające z zastosowania seq
do drugiego argumentu; jak pokazano powyżej, całość jest klasowa clojure.lang.Cons
. W przeciwieństwie do tego, conj
zawsze zwraca zbiór mniej więcej tego samego typu, co przekazana do niego kolekcja. (Z grubsza, ponieważ a PersistentArrayMap
zostanie zamieniony w a, PersistentHashMap
gdy tylko przekroczy 9 wpisów.)
1 Tradycyjnie, w świecie Lispa, cons
cons (tructs a pair), więc Clojure odchodzi od tradycji Lispa polegając na tym, że jego cons
funkcja konstruuje sekwencję, która nie ma tradycyjnego cdr
. Uogólnione użycie cons
wyrażenia „skonstruuj rekord jakiegoś lub innego typu, aby przechowywać razem pewną liczbę wartości” jest obecnie wszechobecne w badaniach języków programowania i ich implementacji; to właśnie ma na myśli, gdy wspomina się o „unikaniu szkód”.