Una differenza è che conj
accetta un numero qualsiasi di argomenti da inserire in una raccolta, mentre ne cons
richiede solo uno:
(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
Un'altra differenza è nella classe del valore restituito:
(class (conj '(1 2 3) 4))
; => clojure.lang.PersistentList
(class (cons 4 '(1 2 3))
; => clojure.lang.Cons
Nota che questi non sono realmente intercambiabili; in particolare, clojure.lang.Cons
non implementa clojure.lang.Counted
, quindi a count
su non è più un'operazione a tempo costante (in questo caso si ridurrebbe probabilmente a 1 + 3 - l'1 deriva dall'attraversamento lineare sul primo elemento, il 3 deriva (next (cons 4 '(1 2 3))
dall'essere a PersistentList
e quindi Counted
).
L'intenzione dietro i nomi è, credo, che cons
significhi costruire un seq 1 , mentre conj
significa congiungere un oggetto a una collezione. Il seq
essendo costruito da cons
inizia con l'elemento passato come primo argomento e ha come next
/ rest
parte la cosa risultante dall'applicazione seq
al secondo argomento; come mostrato sopra, l'intera cosa è di classe clojure.lang.Cons
. Al contrario, conj
restituisce sempre una raccolta approssimativamente dello stesso tipo della raccolta passata. (Approssimativamente, perché a PersistentArrayMap
sarà trasformato in a PersistentHashMap
non appena supera le 9 voci.)
1 Tradizionalmente, nel mondo Lisp, cons
costituisce una coppia, quindi Clojure si discosta dalla tradizione Lisp avendo la sua cons
funzione di costruire un seq che non ha un tradizionale cdr
. L'uso generalizzato di cons
per significare "costruire un record di un tipo o di un altro per tenere insieme un certo numero di valori" è attualmente onnipresente nello studio dei linguaggi di programmazione e della loro implementazione; questo è ciò che si intende quando si parla di "evitare il consumo".