1

I am new to clojure and i have been trying out different programs. Here is my program :

(defn sdsu-reverse [x]
  (loop [n (count x) x x]
  (if (= 0 n)
    (x)
    (recur (- n 1) (conj (next x) (first x))))))

(= (sdsu-reverse [1 2 3 4 5]) [5 4 3 2 1])

I have been getting error : java.lang.ClassCastException: clojure.lang.Cons cannot be cast to clojure.lang.IFn C:\Users\Shalima\Documents\Textbooks\Functional Programming\Programs\sample.clj:44 user/sdsu-reverse

But I cant seem to figure it out. Could you please help me with this ?

Thank you.

4
  • (x) tries to call x (which is a sequence) as a function. All you need there is x. Commented Sep 11, 2014 at 18:42
  • Also (since you're learning) you don't need to count your sequence every time. You just want to check if it's empty. Commented Sep 11, 2014 at 18:55
  • @DiegoBasch Indeed you just want to check if it's empty, but note that the original code only counts it once, not every time. Commented Sep 11, 2014 at 19:00
  • Correct, I thought I saw a count in the comparison. The OP's code (as it is now at least) counts at the start of the loop. It does keep an unnecessary counter though. Commented Sep 11, 2014 at 19:14

2 Answers 2

2

As Alex notes above, you need to replace (x) with x in your if expression. Wrapping x in parentheses treats it as a function when instead you want to return a value.

As for the other issue in your code:

conj is a slightly confusing function.

clojure.core/cons
([x seq])
  Returns a new seq where x is the first element and seq is
    the rest.

Sounds clear enough. But look at what happens when conj is applied to a list versus a vector (source).

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

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

The reason for this has to do with how the vector and list datatypes are constructed. Vectors receive new values from the righthand side; lists, from the lefthand side.

When you call conj (next x) (first x), you effectively are calling conj '(2 3 4) '(1), over and over again. So you end up with the same value that you started at.

A better approach would be to use recursion as follows.

(defn sdsu-reverse [x]
  (if (empty? x)
    nil
    (cons (last x) (sdsu-reverse (drop-last x)))))

I hope this helps.

Edit in response to Leonid's comments.

Leonid is correct that the above will fail for large sequences. Alternatively you could do something like

(defn reverse' 
  ([x] (reverse' x nil))
  ([x acc] (if (empty? x) 
             acc 
             (recur (rest x) (cons (first x) acc)))))
Sign up to request clarification or add additional context in comments.

4 Comments

Using recur is always better than using direct recursion, not only because it's much faster, but also because direct recursion leads to stack overflow. Try reversing something like (range 99999) and you'll see what I mean.
Using last and drop-last instead of first and rest is also a very bad idea, because they are extremely ineffective when applied to sequences.
Agreed. Amended my answer.
Just for the sake of completeness: the simplest and the most efficient way to revert a sequence is to use reduce higher-order function: (reduce conj () x), which is exactly how build-in reverse function works.
0

class cast exception in your code is because you try to make a list from a constant i.e. (x) so just replace it with x you won't get class cast exception.

Comments

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.