1
votes

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.

2
(x) tries to call x (which is a sequence) as a function. All you need there is x. - Alex
Also (since you're learning) you don't need to count your sequence every time. You just want to check if it's empty. - Diego Basch
@DiegoBasch Indeed you just want to check if it's empty, but note that the original code only counts it once, not every time. - amalloy
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. - Diego Basch

2 Answers

2
votes

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)))))
0
votes

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.