Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can somebody explain the behavior of "conj"?

Tags:

clojure

(conj (drop-last "abcde") (last "abcde"))

returns (\e \a \b \c \d)

I am confusing. In the doc of conj, I notice

The 'addition' may happen at different 'places' depending on the concrete type.

Does it mean that for LazySeq, the place to add the new item is the head? How can I get (\a \b \c \d \e) as the result?

like image 955
xiaowl Avatar asked Jul 15 '12 09:07

xiaowl


2 Answers

'The 'addition' may happen at different 'places' depending on the concrete type.'

This refers to the behavior of Clojure's persistent collections that incorporate the addition in the most efficient way with respect to performance and the underlying implementation.

Vectors always add to the end of the collection:

user=> (conj [1 2 3] 4)
[1 2 3 4]

With Lists, conj puts the item at the front of the list, as you've noticed:

user=> (conj '(1 2 3) 4)
(4 1 2 3)

So, yes, a LazySeq is treated like a List with respect to its concrete implementation.

How can I get (\a \b \c \d \e) as the result?

There's a number of ways, but you could easily create a vector from your LazySeq:

(conj (vec (drop-last "abcde"))
      (last "abcde"))
like image 80
Scott Avatar answered Nov 12 '22 19:11

Scott


It is important to realize that conj simply delegates to the implementation of cons on the IPersistentCollection interface in Clojure's Java stuff. Therefore, depending on the given data structure being dealt with it can behave differently.

The intent behind conj is that it will always add an item to the data structure in the way that is most efficient.

For lists the most efficient spot to put it is the front. For vectors the most efficient spot to put it is at the end.

like image 37
Alex Baranosky Avatar answered Nov 12 '22 18:11

Alex Baranosky