I was reading The Joy Of Clojure the first edition and looking at chapter 7, and experimenting the A* path finding code.

And it gives me this error

ClassCastException clojure.lang.LazySeq cannot be cast to java.lang.Comparable  clojure.lang.Util.compare (Util.java:153)

The code is the same with the book. And Clojure didn't print enough stack trace, I can not figure out which line cause the error.

But Clojure provide tools to let you see the full stack trace, and it looks like this

 (.printStackTrace *e)

Now its easy to see where the problem is

java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to java.lang.Comparable
        at clojure.lang.Util.compare(Util.java:153)
        at clojure.lang.APersistentVector.compareTo(APersistentVector.java:424)
        at clojure.lang.Util.compare(Util.java:153)
        at clojure.lang.RT$DefaultComparator.compare(RT.java:278)
        at clojure.lang.PersistentTreeMap.doCompare(PersistentTreeMap.java:311)
        at clojure.lang.PersistentTreeMap.entryAt(PersistentTreeMap.java:298)
        at clojure.lang.PersistentTreeMap.containsKey(PersistentTreeMap.java:94)
        at clojure.lang.APersistentSet.contains(APersistentSet.java:34)
        at clojure.lang.PersistentTreeSet.cons(PersistentTreeSet.java:52)
        at clojure.lang.PersistentTreeSet.cons(PersistentTreeSet.java:17)
        at clojure.lang.RT.conj(RT.java:562)
        at clojure.core$conj.invoke(core.clj:83)
        at clojure.lang.ArrayChunk.reduce(ArrayChunk.java:63)
        at clojure.core.protocols$fn__6093.invoke(protocols.clj:98)
        at clojure.core.protocols$fn__6057$G__6052__6066.invoke(protocols.clj:19)
        at clojure.core.protocols$seq_reduce.invoke(protocols.clj:31)
        at clojure.core.protocols$fn__6078.invoke(protocols.clj:54)
        at clojure.core.protocols$fn__6031$G__6026__6044.invoke(protocols.clj:13)
        at clojure.core$reduce.invoke(core.clj:6289)
        at clojure.core$into.invoke(core.clj:6342)
        at user$astar.invoke(NO_SOURCE_FILE:435)
        at user$eval232.invoke(NO_SOURCE_FILE:539)
        at clojure.lang.Compiler.eval(Compiler.java:6703)
        at clojure.lang.Compiler.eval(Compiler.java:6666)
        at clojure.core$eval.invoke(core.clj:2927)
        at clojure.main$repl$read_eval_print__6625$fn__6628.invoke(main.clj:239)
        at clojure.main$repl$read_eval_print__6625.invoke(main.clj:239)
        at clojure.main$repl$fn__6634.invoke(main.clj:257)
        at clojure.main$repl.doInvoke(main.clj:257)
        at clojure.lang.RestFn.invoke(RestFn.java:421)
        at clojure.main$repl_opt.invoke(main.clj:323)
        at clojure.main$main.doInvoke(main.clj:421)
        at clojure.lang.RestFn.invoke(RestFn.java:397)
        at clojure.lang.Var.invoke(Var.java:375)
        at clojure.lang.AFn.applyToHelper(AFn.java:152)
        at clojure.lang.Var.applyTo(Var.java:700)
        at clojure.main.main(main.java:37)

The *e store the most recent thrown exception. Here the into function throws the exception.

When you call into on a sorted-set, make sure the inputs are all comparable.

For example

user=> (into rest-work-todo [[1 '(23 3)] [1 2]])
ClassCastException clojure.lang.PersistentList cannot be cast to java.lang.Number  clojure.lang.Util.compare (Util.java:152)

Clojure don't know how to compare list and a number.

From the stack trace , we know the input of into function must contains LazySeq which is not comparable.

It turns out that the neighbors function introduced in chapter 5 returns LazySeq.

(defn neighbors
  ([size yx] (neighbors [[-1 0] [1 0] [0 -1] [0 1] ] size yx))
  ([deltas size yx] (filter (fn [new-yx] (every? #(< -1 % size) new-yx)) (map #(map + yx %)  deltas)))

See the output

user=> (neighbors 5 [0 0])
((1 0) (0 1))

This is because when you map on two vector and do addition, the output is a list, not a vector

user=> (class (map + [1 2] [3 4]))

But its not the book's fault, I'm using Clojure 1.6, and the book was written in 2011. Maybe at that time the map on two vector returns vector.

I noticed that there is a function mapv do the thing we want but its introduced in Clojure 1.4 which released in 2012.

user=> (class (mapv + [1 2] [3 4]))

So, if you are using recent version of Clojure, you should modify the neighbors like this

(defn neighbors
  ([size yx] (neighbors [[-1 0] [1 0] [0 -1] [0 1] ] size yx))
  ([deltas size yx] (filter (fn [new-yx] (every? #(< -1 % size) new-yx)) (map #(mapv + yx %)  deltas)))