4

I'm currently going through the 4clojure Problem 23

My current solution uses recursion to go through the list and append each element to the end of the result of the same function:

(fn self [x] (if (= x []) 
                   x 
             (conj (self (rest x)) (first x))
))

But when I run it against [1 2 3] it gives me (1 2 3)
What I think it should be doing through recursion is:

(conj (conj (conj (conj (conj [] 5) 4) 3) 2) 1)

which does return

[5 4 3 2 1]

But it is exactly the opposite, so I must be missing something. Also, I don't understand why ones return a vector and the other one returns a list.

1 Answer 1

6

When you do (rest v) you're getting a list (not a vector), and then conj is appending to the front each time (not the back):

user=> (defn self [v] (if (empty? v) v (conj (self (rest v)) (first v))))
#'user/self
user=> (self [1 2 3])
(1 2 3)
user=> (defn self [v] (if (empty? v) [] (conj (self (rest v)) (first v))))
#'user/self
user=> (self [1 2 3])
[3 2 1]
user=>
user=> (rest [1])
()
user=> (conj '() 2)
(2)
user=> (conj '(2) 1)
(1 2)
user=>
Sign up to request clarification or add additional context in comments.

5 Comments

although I understand now the reason (efficiency) it strikes me as weird having the same name for a function with a different behaviour. But thank you for the explanation, it'll probably stick from now on :)
@Willyfrog: well the behaviour is simply "adding", without saying where (and (doc conj) mentions it). For example you can also conj to, say, a set: (conj #{:a :c} :b)
@Willyfrog You can use cons to always append to the front.
conj adds to the end of a vector or the beginning of a list.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.