Reputation: 145
Why does into
behave differently when the collection being inserted into is different? For example:
user=> (into [] [1 2 3])
[1 2 3]
So far, so good. Exactly as I would expect. However:
user=> (into () [1 2 3])
(3 2 1)
Why does this reverse the arguments? I assume it's for performance, and the items are inserted sequentially with cons
? This still seems to break the abstraction to me, in two differently typed ordered collections I would expect the result to be ordered consistently.
Upvotes: 2
Views: 156
Reputation: 1593
As an addendum to @MarkFisher 's answer: into
is analogous to reduce conj
; the difference of behaviour of into
follows from the difference in behaviour of conj
:
(conj '(:b :c) :a) ;; '(:a :b :c) ;; prepend to lists
(conj [:a :b] :c) ;; [:a :b :c] ;; append to vectors
(conj #{:a :b} :c) ;; #{:a :b :c} ;; add to sets
(conj #{:a :b :c} :c) ;; #{:a :b :c} ;; nothing if already there
(conj {:a 1 :b 2} [:c 3]) ;; {:a 1 :b 2 :c 3} ;; add key-value
(conj {:a 1 :b 2 :c 3} [:c 4]) ;; {:a 1 :b 2 :c 4} ;; replace value if present
EDIT: I recently used conj
's polymorphism at my advantage. Writing a palindrome generator, the same function could be used to generate both head and tail of the palindrome, simply by feeding either a vector or a list.
Upvotes: 0
Reputation: 9886
into
is conj
and seq
together.
conj adds to lists at the beginning, and vectors at the end for efficiency so that there is no traversal of either type in order to add to it.
This is explained nicely in Programming Clojure when talking about the Collection abstraction in Clojure:
These functions (conj/seq/count/empty/=) are all polymorphic with regard to the concrete type of collection being operated upon. Said another way, each operation provides semantics consistent with the constraints of each data structure implementation.
Upvotes: 7