【问题标题】:Creating clojure add function using recursion使用递归创建 clojure 添加函数
【发布时间】:2013-01-29 17:28:41
【问题描述】:

我正在尝试使用 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)

【问题讨论】:

    标签: recursion clojure


    【解决方案1】:

    您的括号似乎有误——您的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 和内置的序列处理函数。

    【讨论】:

    • 但这不会导致堆栈溢出。第一次调用x绑定(1),第二次及后续绑定(()),不为空。一个选项是(apply addall (rest x))
    • 啊,这更有意义,你知道我将如何在理论上使用 & 来解决这个问题吗?我将如何以递归方式分解参数?
    • @LinuxN00b 好问题——我已将其编辑为我的答案。祝你好运!
    【解决方案2】:

    我想这就是你想要的:

    (defn addall ([x] (if (empty? x) 0 (+ (first x) (addall (rest x))))))
    

    正如 Matt Fenwick 所说,您应该使用循环/递归。更惯用的方法是使用 reduce:

    (reduce + [1 2 3 4 5])
    

    clojure 中有很多很棒的工具,而且您通常不需要循环/递归或显式递归之类的东西。

    【讨论】:

    • 当我添加 & 运算符时,您的代码仍然出现堆栈溢出错误。我知道 reduce 将是做到这一点的聪明方法,但是我试图了解如何从头开始正确创建递归函数以完全理解它
    猜你喜欢
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 2021-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多