如何将此写为递归Clojure函数?

use*_*565 1 recursion sum clojure

我将用Python描述我想做什么(我想在Clojure中写这个).我有这个功能:

def f(n):
    s=0
    for d in range(1,n+1):
        s+=d*(n//d)
    return(s)
Run Code Online (Sandbox Code Playgroud)

这基本上是从d = 1到n包含循环,并且总结了d/d的最低值的d倍的值.

在Clojure中我想让它成为一个递归函数.Python等价物:

def f(d, n):
    if d == 0: return 0
    else: return d*(n//d) + f(d-1, n)
Run Code Online (Sandbox Code Playgroud)

然后我会调用函数f(n, n).

我在尝试这个:

(defn f
     ([n] (f n n))
     ([d n]
      (if (> d 0)
         (recur (dec d) n)
        0)))
Run Code Online (Sandbox Code Playgroud)

但是我不知道到目前为止这是否正确,或者在总和或者如何做到这一点等等.

Thu*_*ail 6

如果你看看你的Clojure f函数,那么[d n]arity会再次出现

  • d 递减和
  • n 不变

...... d当它返回时为零0.

如果我们将这个arity写成一个独特的本地函数,使用letfn,我们可以删除不变的n参数,从f参数中提取它:

(defn f [n]
  (letfn [(g [d]
           (if (> d 0)
               (recur (dec d))
               0))]
    (g n)))
Run Code Online (Sandbox Code Playgroud)

这当然会产生错误的答案,总是返回0:

(f 10)
=> 0
Run Code Online (Sandbox Code Playgroud)

但我们可以看到将总和放在哪里:

(defn f [n]
  (letfn [(g [d]
           (if (> d 0)
               (+  (* d (quot n d)) (g (dec d)))
               0))]
    (g n)))
Run Code Online (Sandbox Code Playgroud)

我们必须将其恢复recur为显式的递归调用g,因为它被包围了+.

但至少它有效:

(f 10)
=> 87
Run Code Online (Sandbox Code Playgroud)

在Clojure中我想让它成为一个递归函数.

别.我上面已经做过,只是为了告诉你计算的位置.

在惯用语Clojure中,显式递归很少见.更好地使用封装其常见模式的函数.我不会重复Carciginate给出的内容,但是一旦你习惯了线程宏,我认为你会发现以下简洁明了:

(defn f [n]
  (->> (range 1 (inc n))
       (map (fn [d] (* d (quot n d))))
       (reduce +)))
Run Code Online (Sandbox Code Playgroud)

顺便说一下,Python代码的合理模拟是

  (defn f [n]
    (loop [s 0, d 1]
      (if (> d n)
          s
          (recur (+ s (* d (quot n d))) (inc d)))))
Run Code Online (Sandbox Code Playgroud)