Recursion 在Clojure中递归求三的所有倍数的和

Recursion 在Clojure中递归求三的所有倍数的和,recursion,clojure,lisp,Recursion,Clojure,Lisp,您好,我对Clojure/Lisp编程有点陌生,但我以前在类似C语言中使用过递归,我编写了以下代码,将1到100之间可以除以3的所有数字相加 (defn is_div_by_3[number] (if( = 0 (mod number 3)) true false) ) (defn sum_of_mult3[step,sum] (if (= step 100) sum ) (if (is_div_by_3 step) (sum_of_mult3

您好,我对Clojure/Lisp编程有点陌生,但我以前在类似C语言中使用过递归,我编写了以下代码,将1到100之间可以除以3的所有数字相加

(defn is_div_by_3[number]
  (if( = 0 (mod number 3))
    true false) 
 )

(defn sum_of_mult3[step,sum]
  (if (= step 100)
    sum
    )
  (if (is_div_by_3 step)
    (sum_of_mult3 (+ step 1 ) (+ sum step)) 
    )
  )
我的想法是在步骤达到sum时结束递归,然后我将在我返回的sum变量中得到我需要的所有倍数,但是我的REPL似乎对这两个变量都返回nil,这里可能有什么错误

是一个表达式而不是语句
if
的结果始终是其中一个分支。事实上,Clojure并没有声明:

Clojure程序由表达式组成。编译器将未经特殊窗体或宏专门处理的每个窗体视为一个表达式,对其求值以生成一个值。没有声明或语句,尽管有时可能会对表达式的副作用进行评估,并忽略其值

有一本适合初学者的在线(免费)好书:

另外,Lisps中的括号并不等同于C族语言中的大括号。例如,我会将您的
is_div_by_3
函数编写为:

(defn div-by-3? [number]
  (zero? (mod number 3)))
对于
sum\u of_mult3
函数,我还将使用更惯用的方法:

(defn sum-of-mult-3 [max] 
  (->> (range 1 (inc max))
       (filter div-by-3?)
       (apply +)))

我认为这段代码在意图上比递归版本更具表现力。唯一的技巧是线程的最后一个宏。查看线程最后一个宏的解释。

此代码存在一些问题

1) 你的第一个
if
sum\u mult3
中是一个noop。它返回的任何内容都不会影响函数的执行

2) 第二个
if
sum\u of_mult3
中只有一个条件,如果步长是3的倍数,则为直接递归。对于大多数数字,第一个分支将不被采用。第二个分支只是一个隐式的
nil
。无论输入如何,函数都保证返回该参数(即使提供的第一个参数是三的倍数,下一个重复出现的值也不会返回)

3) 如果可能,使用
recur
而不是self调用,self调用消耗堆栈,
recur
编译成一个不消耗堆栈的简单循环

最后,一些风格问题:

1) 始终将关闭参数与其关闭的块放在同一行上。这使得Lisp风格的代码更具可读性,如果没有其他东西的话,我们大多数人也会阅读Algol风格的代码,把paren放在正确的位置会提醒我们正在阅读哪种语言

2)
(如果(=0(型号3))真-假)
(=0(型号3)
相同,后者又与
(零)(型号3)相同)

3) 使用
(inc x)
代替
(+x 1)

4) 对于两个以上的潜在操作,请使用
case
cond
condp

(defn sum-of-mult3
  [step sum]
  (cond (= step 100) sum
        (zero? (mod step 3)) (recur (inc step) (+ sum step))
        :else (recur (inc step) sum))

除了罗德里戈的答案之外,我想到的解决问题的第一个方法是:

(defn sum-of-mult3 [n]
  (->> n
       range
       (take-nth 3)
       (apply +)))
这应该是不言自明的。这里有一种不使用序列的更“数学”的方法,考虑到所有数字的总和(N*(N+1))/2(N*(N+1))


正如Rodrigo所说,递归不是完成这项任务的正确工具。

作为一名学习者(不仅仅是回答你),仅仅迭代三的倍数不是更有效吗?e、 例如
(reduce+(take while#)(<%100)(iterate(partial+3)0))
。迂腐的观察:你不需要你的范围从1开始,而不是默认的0。@DiegoBasch我知道,我这样做是因为我认为它会更清晰。
(defn sum-of-mult3* [n]
  (let [x (quot (dec n) 3)]
    (* 3 x (inc x) 1/2)))