我正试着用clojure包围递归。我使用以下代码收到堆栈溢出错误,有人能发现问题吗?
(我知道这是低效的,但它严格用于学习目的)
user=> (defn addall
([] 0)
([& x]
(if (empty? x) 0)
(+ (first x) (addall (rest x)))))
user/addall
user=> (addall 1)
StackOverflowError clojure.lang.ArraySeq.next (ArraySeq.java:78)
答案 0 :(得分:7)
看来您的括号内容有误 - 您的if
需要else
表单。我怀疑你的意思是:
(defn addall
([] 0)
([& x]
(if (empty? x)
0 ;;; <=== no ')' after 0
(+ (first x) (addall (rest x)))))) ;;; <== extra ')' here
但即使修复了这个问题,你的代码仍然是错误的:它假定它是用多个参数调用的 - (addall 1 2 3)
- 但是通过传递一个列表 - (addall [2 3])
来重复。这导致它卡在一个没有任何进展的循环中,你可以通过添加print
语句来观察:
(defn addall
([] 0)
([& x]
(print (str "new x: " x "\n"))
(if (empty? x)
0 ;;; <=== no ')' after 0
(+ (first x) (addall (rest x))))))
这实际上在我的电脑上产生了一个段错误!
此外,它有两个基本情况。我建议改为:
(defn addall
[xs]
(if (empty? xs)
0
(+ (first xs)
(addall (rest xs)))))
使用向量调用:
(addall [1 2 3])
或者,如果您想使用可变参数函数,您还需要apply
:
(defn addall
[& x]
(print (str "new x: " x "\n"))
(if (empty? x)
0
(+ (first x)
(apply addall (rest x))))) ;;; <=== apply addall
那就是说,你应该注意到Clojure没有尾调用优化,这意味着这个代码会因中等大小的输入而失败。 Clojure鼓励使用loop/recur
和内置序列处理函数。
答案 1 :(得分:0)
我认为这就是你想要的:
(defn addall ([x] (if (empty? x) 0 (+ (first x) (addall (rest x))))))
如Matt Fenwick所述,你应该使用loop / recur。更惯用的方法是使用reduce:
(reduce + [1 2 3 4 5])
clojure中有很多很棒的工具,通常你不需要循环/重复或显式递归。