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”.
(cons foo nil)
zwraca singletonPersistentList
(i podobnie dlaconj
).Rozumiem, że to, co mówisz, jest prawdą: spójność na liście jest równoważna minusom na liście.
Możesz myśleć o koniunkcji jako o operacji „wstawiania gdzieś”, a wadach jako o operacji „wstawiania na początku”. Na liście najbardziej logiczne jest wstawienie na początku, więc w tym przypadku spójniki i wady są równoważne.
źródło
Inną różnicą jest to, że ponieważ
conj
jako pierwszy argument przyjmuje sekwencję, dobrze gra zalter
aktualizacją aref
do jakiejś sekwencji:Zasadniczo działa to
(conj a-sequence-ref an-item)
w sposób bezpieczny dla wątków. To by nie zadziałałocons
. Zobacz rozdział o współbieżności w Programming Clojure autorstwa Stu Halloway, aby uzyskać więcej informacji.źródło
Inną różnicą jest zachowanie listy?
źródło
W bibliotece Tupelo znajdują się dedykowane funkcje, które pozwalają dodawać wartości dołączane lub poprzedzające do dowolnej kolekcji sekwencyjnej:
źródło