2015-02-09 30 views
2

您好我对Clojure/Lisp编程有点新,但我曾经在C语言中使用过递归,我写了下面的代码将所有可以除以三的数字相加1 100 在Clojure中递归地总结所有的三倍数Clojure

(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)) 
    ) 
) 

之间

我的想法是,当步长达到总和结束递归,那么我将有我需要的和可变的,我回报倍数,但我的REPL似乎两个返回nil变量这里可能是错误的吗?

+0

我自己是一个学习者(而不仅仅是对你的吸引),只是迭代三次的倍数不会更有效吗?例如比如'(reduce +(take-while#(<%100)(iterate(partial + 3)0)))'。 – cfrick 2015-02-09 18:06:42

回答

1

这段代码有几个问题。

1)您的第一个ifsum_of_mult3是一个noop。它返回的任何内容都可以影响该函数的执行。

2)第二个ifsum_of_mult3只有一个条件,直接递归,如果步骤是3的倍数。对于大多数数字,第一个分支将不会被采取。第二个分支只是一个隐含的nil。无论输入如何,你的函数都能保证返回(即使提供的第一个参数是三的倍数,下一个重现值不会)。 3)在可能的情况下,使用recur而不是自我调用,自我调用消耗堆栈,recur编译为不消耗堆栈的简单循环。

最后,一些作风问题:

1)始终把与他们正在缩小块的同一行关闭的括号。这使得Lisp样式代码更具可读性,而且如果我们大多数人都没有阅读过Algol样式代码,并且将Parens放在正确的位置,这会提醒我们我们正在阅读哪种语言。

2)(if (= 0 (mod number 3)) true false)相同(= 0 (mod number 3)这又是相同的(zero? (mod number 3))

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

4),用于两个以上的潜在动作,使用casecond,或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)) 
4

if表达不是陈述if的结果始终是其中的一个分支。事实上,Clojure没有陈述如下:here

Clojure程序由表达式组成。每个没有被特殊格式或宏特别处理的表单都被编译器视为一个表达式,它被评估为产生一个值。没有声明或陈述,尽管有时可能会评估表达式的副作用并忽略它们的值。

有一个很好的在线(免费)的书,适合初学者:http://www.braveclojure.com

其他的事情,的Lisp括号并不等同于在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 +))) 

我认为这个代码是在它的意图更富于表现力然后是递归版本。唯一的技巧是->>线程最后的宏。请看this answer以获取线程最后一个宏的解释。

+0

迂腐观察:你不需要你的范围从1开始,而不是默认值0. – 2015-02-09 23:39:26

+0

@DiegoBasch我知道,我这么做是因为我认为它会更清楚。 – 2015-02-09 23:47:14

0

除了罗德里戈的回答,这是我第一个想到解决问题的方法e问题:

(defn sum-of-mult3 [n] 
    (->> n 
     range 
     (take-nth 3) 
     (apply +))) 

这应该是不言自明的。下面是不使用序列更“数学”的方式,考虑到所有数字多至N个包容性的总和(N *(N + 1))/ 2。

(defn sum-of-mult3* [n] 
    (let [x (quot (dec n) 3)] 
    (* 3 x (inc x) 1/2))) 

像罗德里戈说,递归不是这项任务的正确工具。