4Clojure斐波那契单函数实现报错:PersistentList无法转换为IFn
解决4Clojure斐波那契匿名函数提交的ClassCastException问题
看样子你在攻克4Clojure的斐波那契习题时遇到了小麻烦——已经用命名函数实现了功能,但打包成单个匿名函数提交时触发了类型转换错误。先看看你的现有实现和问题代码:
你已经验证过的命名函数版本:
(defn nth-fibo [i] (cond (= i 1) 1 (= i 2) 1 :else (+ (nth-fibo (- i 1)) (nth-fibo (- i 2))))) (defn fibos [i] (loop [x i] (when (> x 0) (cons (nth-fibo x) (fibos (- x 1)))))) (reverse (fibos 5)) ; 返回 (1 1 2 3 5),符合预期
但你尝试转成匿名函数提交时写了这段代码,触发了java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.IFn错误:
#( (letfn [ (nth-fibo [i] (cond (= i 1) 1 (= i 2) 1 :else (+ (nth-fibo (- i 1)) (nth-fibo (- i 2))))) (fibos [i] (loop [x i] (when (> x 0) (cons (nth-fibo x) (fibos (- x 1)))))) ] (reverse (fibos %))))
错误原因
问题出在匿名函数体最外层的多余括号上!你写的#( (letfn ...) )相当于把letfn表达式计算出来的斐波那契列表当成了一个函数去调用——但列表并不是可调用的函数,所以JVM抛出了类型转换异常。
修复方法
只需要去掉letfn外面的那一层括号,让匿名函数直接返回letfn表达式的结果就行:
#(letfn [ (nth-fibo [i] (cond (= i 1) 1 (= i 2) 1 :else (+ (nth-fibo (- i 1)) (nth-fibo (- i 2))))) (fibos [i] (loop [x i] (when (> x 0) (cons (nth-fibo x) (fibos (- x 1)))))) ] (reverse (fibos %)))
额外优化:更高效的实现
不过你当前的实现是递归计算每个斐波那契数,会有大量重复计算(比如计算第5个数时会重复计算第3、2、1个数很多次),效率偏低。推荐用迭代或者iterate的方式实现,更简洁高效:
迭代版本
#(loop [n % a 1 b 1 acc []] (cond (= n 0) acc (= n 1) (conj acc a) :else (recur (dec n) b (+ a b) (conj acc a))))
更简洁的iterate版本
#(take % (map first (iterate (fn [[a b]] [b (+ a b)]) [1 1])))
这个版本用iterate持续生成斐波那契数对[a b],每次迭代生成下一对[b, a+b],然后取每个对的第一个元素,最后取前N个,完全符合你的需求,代码也更简洁。
内容的提问来源于stack exchange,提问作者Terrence Brannon
相关产品推荐
相关产品推荐

