在 Clojure 中递归求和所有三的倍数
Summing all the multiples of three recursively in Clojure
嗨,我对 Clojure/Lisp 编程有点陌生,但我以前在 C 之类的语言中使用过递归,我编写了以下代码来对 1 到 100 之间所有可以被三除的数字求和。
(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))
)
)
我的想法是在 step 达到总和时结束递归,然后我将在我 return 的总和变量中得到我需要的所有倍数,但我的 REPL 似乎 returning nil对于这两个变量,这里可能有什么问题?
if
is an expression not a statement. The result of the if
is always one of the branches. In fact Clojure doesn't have statements has stated here:
Clojure programs are composed of expressions. Every form not handled specially by a special form or macro is considered by the compiler to be an expression, which is evaluated to yield a value. There are no declarations or statements, although sometimes expressions may be evaluated for their side-effects and their values ignored.
有一本适合初学者的不错的在线(免费)书籍:http://www.braveclojure.com
另外,Lisps 中的圆括号不等同于 C 系列语言中的大括号。例如,我会将您的 is_div_by_3
函数写为:
(defn div-by-3? [number]
(zero? (mod number 3)))
我还会对 sum_of_mult3
函数使用更惯用的方法:
(defn sum-of-mult-3 [max]
(->> (range 1 (inc max))
(filter div-by-3?)
(apply +)))
我认为这段代码比递归版本更能表达其意图。唯一的技巧是 ->>
thread last macro. Take a look at 用于解释线程最后一个宏。
此代码存在一些问题。
1) 您在 sum_of_mult3
中的第一个 if
是空话。 returns 不会影响函数的执行。
2) sum_of_mult3
中的第二个 if
只有一个条件,如果步长是 3 的倍数则直接递归。对于大多数数字,不会采用第一个分支。第二个分支只是一个隐含的 nil
。无论输入如何,您的函数都保证return(即使提供的第一个参数是三的倍数,下一个重复值也不会)。
3) 尽可能使用 recur
而不是自我调用,自我调用会消耗堆栈,recur
编译成一个不消耗堆栈的简单循环。
最后,一些样式问题:
1) 始终将右括号与要关闭的块放在同一行。这使得 Lisp 风格的代码更具可读性,如果不出意外的话,我们大多数人也会阅读 Algol 风格的代码,将括号放在正确的位置会提醒我们正在阅读哪种语言。
2) (if (= 0 (mod number 3)) true false)
与 (= 0 (mod number 3)
相同,后者又与 (zero? (mod number 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 +)))
这应该是不言自明的。这里有一个不使用序列的更 "mathematical" 的方法,考虑到所有数字的总和直到 N 包括在内是 (N * (N + 1)) / 2.
(defn sum-of-mult3* [n]
(let [x (quot (dec n) 3)]
(* 3 x (inc x) 1/2)))
正如 Rodrigo 所说,递归不是完成此任务的正确工具。
嗨,我对 Clojure/Lisp 编程有点陌生,但我以前在 C 之类的语言中使用过递归,我编写了以下代码来对 1 到 100 之间所有可以被三除的数字求和。
(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))
)
)
我的想法是在 step 达到总和时结束递归,然后我将在我 return 的总和变量中得到我需要的所有倍数,但我的 REPL 似乎 returning nil对于这两个变量,这里可能有什么问题?
if
is an expression not a statement. The result of the if
is always one of the branches. In fact Clojure doesn't have statements has stated here:
Clojure programs are composed of expressions. Every form not handled specially by a special form or macro is considered by the compiler to be an expression, which is evaluated to yield a value. There are no declarations or statements, although sometimes expressions may be evaluated for their side-effects and their values ignored.
有一本适合初学者的不错的在线(免费)书籍:http://www.braveclojure.com
另外,Lisps 中的圆括号不等同于 C 系列语言中的大括号。例如,我会将您的 is_div_by_3
函数写为:
(defn div-by-3? [number]
(zero? (mod number 3)))
我还会对 sum_of_mult3
函数使用更惯用的方法:
(defn sum-of-mult-3 [max]
(->> (range 1 (inc max))
(filter div-by-3?)
(apply +)))
我认为这段代码比递归版本更能表达其意图。唯一的技巧是 ->>
thread last macro. Take a look at
此代码存在一些问题。
1) 您在 sum_of_mult3
中的第一个 if
是空话。 returns 不会影响函数的执行。
2) sum_of_mult3
中的第二个 if
只有一个条件,如果步长是 3 的倍数则直接递归。对于大多数数字,不会采用第一个分支。第二个分支只是一个隐含的 nil
。无论输入如何,您的函数都保证return(即使提供的第一个参数是三的倍数,下一个重复值也不会)。
3) 尽可能使用 recur
而不是自我调用,自我调用会消耗堆栈,recur
编译成一个不消耗堆栈的简单循环。
最后,一些样式问题:
1) 始终将右括号与要关闭的块放在同一行。这使得 Lisp 风格的代码更具可读性,如果不出意外的话,我们大多数人也会阅读 Algol 风格的代码,将括号放在正确的位置会提醒我们正在阅读哪种语言。
2) (if (= 0 (mod number 3)) true false)
与 (= 0 (mod number 3)
相同,后者又与 (zero? (mod number 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 +)))
这应该是不言自明的。这里有一个不使用序列的更 "mathematical" 的方法,考虑到所有数字的总和直到 N 包括在内是 (N * (N + 1)) / 2.
(defn sum-of-mult3* [n]
(let [x (quot (dec n) 3)]
(* 3 x (inc x) 1/2)))
正如 Rodrigo 所说,递归不是完成此任务的正确工具。