Una differenza è che conj
accetta qualsiasi numero di argomenti da inserire in una collezione, mentre cons
vuole solo un:
(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 di ritorno:
(class (conj '(1 2 3) 4))
; => clojure.lang.PersistentList
(class (cons 4 '(1 2 3))
; => clojure.lang.Cons
Si noti che questi non sono realmente intercambiabili; in particolare, clojure.lang.Cons
non implementa clojure.lang.Counted
, quindi un count
su di esso non è più un'operazione a tempo costante (in questo caso si ridurrebbe probabilmente a 1 + 3 - il 1 deriva da traversal lineare sul primo elemento, il 3 viene da (next (cons 4 '(1 2 3))
è un PersistentList
e quindi Counted
).
L'intenzione dietro i nomi è, credo, che cons
significa cons (truct un ss) , mentre conj
significa conj (oin un elemento su una collezione). Il seq
viene costruito da cons
inizia con l'elemento passato come primo argomento e ha come parte next
/rest
la cosa risultante dall'applicazione di seq
al secondo argomento; come mostrato sopra, il tutto è della classe clojure.lang.Cons
. Al contrario, conj
restituisce sempre una raccolta di circa lo stesso tipo della raccolta passata. (Approssimativamente, perché un PersistentArrayMap
sarà trasformato in un PersistentHashMap
appena cresce oltre 9 voci.)
Tradizionalmente, nel mondo Lisp, cons
cons (tructs una coppia), così Clojure parte dalla tradizione Lisp per avere la sua funzione cons
costruire un seq che non ha un tradizionale cdr
. L'uso generalizzato di cons
per indicare "costruire un record di un tipo o altro per contenere insieme un numero di valori" è attualmente onnipresente nello studio dei linguaggi di programmazione e della loro implementazione; questo è ciò che si intende quando viene menzionato "evitando il consing".
fonte
2010-06-09 20:38:30
Che articolo fantastico! Non ero a conoscenza del fatto che esistesse un tipo di contro. Molto bene! –
Grazie. Sono felice di sentirlo. :-) –
Per inciso, come caso speciale, '(cons foo nil)' restituisce un singleton 'PersistentList' (e allo stesso modo per' conj'). –