10

Clojure:

1:13 user=> (first (conj '(1 2 3) 4))
4
1:14 user=> (first (conj [1 2 3] 4))
1
; . . .
1:17 user=> (first (conj (seq [1 2 3]) 4))
4

I understand what is going on, but should this work differently?

compman
  • 2,174
  • 2
  • 18
  • 26
  • I have been learning Clojure since May of this year. I found delving into exercises like this to be very helpful, especially given I never learned a Lisp-like language before Clojure. – octopusgrabbus Sep 15 '11 at 22:51

2 Answers2

20

Documentation for conj (from clojure.org):

conj[oin]. Returns a new collection with the xs 'added'. (conj nil item) returns (item). The 'addition' may happen at different 'places' depending on the concrete type.

It's more efficient to "add" elements to the end of a vector, while it's more efficient to do so at the beginning of lists. conj uses whatever is the most efficient for the data structure you give it.

In the examples you give, '(1 2 3) and (seq [1 2 3]) both implement ISeq (see documentation for seq?), while [1 2 3] doesn't.

Clojure's conj ultimately calls the cons method (not to be confused with the cons function - this method is internal clojure code) on the underlying data structure; for vectors (PersistentVector), cons adds elements to the end, while for lists they're added to the front (the cons method for PersistentLists returns a new list with the new element as its head, and the existing list as its tail).

Gert
  • 3,839
  • 19
  • 22
  • The last paragraph I think is incorrect (at least in Clojure 1.2.1): `(cons 4 [1 2 3])`, for example, does not append the element but prepends it, resulting in `(4 1 2 3)`. The rest of the answer, though, is absolutely correct. – Zach L Sep 15 '11 at 23:13
  • You are right, Zach, but Clojure's `cons` function (implemented in `Clojure.lang.RT/cons`) is different from the `cons` methods implemented in `PersistentVector`, `PersistentList` et cetera. – Gert Sep 15 '11 at 23:22
  • Ah, now I understand you. The way it's phrased, it sounds like you are referring to the core function `cons`. – Zach L Sep 15 '11 at 23:25
  • fair enough - I edited my answer to make it clearer. Thanks for your feedback! – Gert Sep 15 '11 at 23:43
6

If you look at Clojure Data Structures

you'll see that conj works differently with lists and vectors.

conj puts the added item at the front of the list and at the end of a vector.

I also suggest looking at Clojure API conj

which has some nice examples. ClojureDocs overall has some very nice examples for most Clojure commands.

octopusgrabbus
  • 10,555
  • 15
  • 68
  • 131