Clojure中的ClassCastException

时间:2014-09-11 18:37:11

标签: clojure

我是clojure的新手,我一直在尝试不同的程序。这是我的计划:

(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])

我遇到了错误:java.lang.ClassCastException:clojure.lang.Cons无法强制转换为clojure.lang.IFn C:\ Users \ Shalima \ Documents \ Textbooks \ Functional Programming \ Programs \ sample.clj:44 user / sdsu-reverse

但我似乎无法弄明白。你能帮帮我吗?

谢谢。

2 个答案:

答案 0 :(得分:1)

正如Alex上面所述,您需要在if表达式中将(x)替换为x。在括号中包装x会将其视为一个函数,而不是要返回一个值。

至于代码中的其他问题:

conj是一个有点令人困惑的功能。

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

听起来很清楚。但请看一下将conj应用于列表与向量(source)时会发生什么。

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

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

其原因与如何构造vector和list数据类型有关。向量从右侧接收新值;列表,从左侧。

当您致电conj (next x) (first x)时,您实际上一遍又一遍地呼叫conj '(2 3 4) '(1)。所以你最终会得到与你开始时相同的价值。

更好的方法是使用递归,如下所示。

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

我希望这会有所帮助。

编辑以回应列昂尼德的评论。

Leonid是正确的,上面的大序列会失败。或者,您可以执行类似

的操作
(defn reverse' 
  ([x] (reverse' x nil))
  ([x acc] (if (empty? x) 
             acc 
             (recur (rest x) (cons (first x) acc)))))

答案 1 :(得分:0)

代码中的类强制转换异常是因为您尝试从常量中创建列表 即(x)所以只需用x替换它就不会获得类别转换异常。