我将用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)))
但是我不知道到目前为止这是否正确,或者在总和或者如何做到这一点等等。
答案 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)))