使用递归创建clojure添加函数

时间:2013-01-29 17:28:41

标签: recursion clojure

我正试着用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)

2 个答案:

答案 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中有很多很棒的工具,通常你不需要循环/重复或显式递归。