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

时间:2017-11-12 10:19:35

标签: recursion clojure sum

我将用Python描述我想要做的事情(我想在Clojure中写这个)。我有这个功能:

def f(n):
    s=0
    for d in range(1,n+1):
        s+=d*(n//d)
    return(s)

基本上是从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)

然后我用f(n, n)调用该函数。

我正在尝试这个:

(defn f
     ([n] (f n n))
     ([d n]
      (if (> d 0)
         (recur (dec d) n)
        0)))

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

3 个答案:

答案 0 :(得分:6)

如果你看一下你的Clojure f函数,[d n] arity会再现

  • d递减并
  • n未更改

...直到d为零,当它返回0时。

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

(defn f [n]
  (letfn [(g [d]
           (if (> d 0)
               (recur (dec d))
               0))]
    (g n)))

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

(f 10)
=> 0

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

(defn f [n]
  (letfn [(g [d]
           (if (> d 0)
               (+  (* d (quot n d)) (g (dec d)))
               0))]
    (g n)))

我们必须将recur还原为对g的显式递归调用,因为它被+包围。

但至少它有效:

(f 10)
=> 87
  

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

唐'吨。我上面已经做过,只是为了告诉你计算的位置。

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

(defn f [n]
  (->> (range 1 (inc n))
       (map (fn [d] (* d (quot n d))))
       (reduce +)))

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

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

答案 1 :(得分:1)

我设法通过3种方式工作。不幸的是,这个算法似乎不适合很好的递归。

为了获得安全的递归,我不得不引入第三个参数。我只是无法安排它,所以recur处于尾部位置。我也决定数数而不是下降。我不认为这里有任何遗留的东西,不幸的是它确实很长。

(defn f3
  ([n] (f3 n 1 0))
  ([n d s]
   (if (> d (inc n))
     s
     (recur n (inc d)
            (+ s (* d (quot n d)))))))

(f3 10)

如果不安全的递归是可以的,这可以简化很多。我没有添加多个参数列表,而是决定允许d使用& [d?]]进行默认,然后再进行检查。我倾向于避免添加多个参数列表,因为par-infer很难处理使其工作所需的缩进。由于recur如何处理var args,第一种方法无法实现此技巧。它仅适用于您未使用recur,或者您使用recur但仅解构1 var-arg的情况。

(defn f2 [n & [d?]]
  (let [d (or d? 1)]
    (if (> d (inc n))
      0
      (+ (f2 n (inc d)) (* d (quot n d))))))

(f2 10)

除非你真的需要递归,否则我只是把它写成地图并减少:

(defn f1 [n]
  (reduce + 0
    (map #(* % (quot n %)))
      (range 1 (inc n)))))

(f1 10)

对我而言,它的整洁程度(不使用线程宏。请参阅缩略图的答案)。

答案 2 :(得分:-1)

试试这个:

(defn f
 ([n] (f n n))
 ([d n]
  (if (> d 0)
     (+ (* d (quot n d)) (recur (dec d) n))
    0)))