2016-11-10 96 views
1

我正在处理clojure中的递归,我并不真正了解它。 我从here做了一个小程序,试图找到从1到20的所有数字可以分开的小数字。这是我编写的代码,但是肯定会有一些遗漏,因为它不起作用。 你能帮我一下吗?谢谢!clojure中的函数递归

(defn smallest [nume index] 
(while(not (= index 0)) 
    (do 
     (cond 
      (zero?(mod nume index))(let [dec' index] (smallest nume index)) 
      :else (let [inc' nume] (smallest nume index)))))) 

编辑: 看起来是更好的loop/recur,所以我试了一下:

(loop [nume 20 
      index 20] 
     (if (= index 0) 
     (println nume) 
     (if (zero?(mod nume index)) 
       (recur nume (dec index)) 
       (recur (inc nume) 20))))) 

工作。如果您对结果感到好奇 - > 232792560

+0

投资于理解循环/复发,不变性和标准库系列变换功能 - 'while'是势在必行的循环结构这在我的经验,一个从来没有使用超过一年一次或两次以上。 –

+0

看来你是在黑暗中拍摄..例如,你认为'(索引20)'做了什么?而且,在“复发”中,价值的顺序很重要,我不确定你是否按照自己的想法去做。 – Shlomi

+0

我刚刚编辑了关于订单的问题。我的意思是(索引20)'是将索引再次设置为20。 @shlomi – Capie

回答

1

while不会做您认为的事。

在clojure中,一切(好,差不多)都是不可变的,这意味着如果index为0,它在相同的上下文中将始终为0。因此,循环直到1是没有意义的。

有很多方法可以帮助您理解loop/recur,您可以通过多种方式实现您想要做的,第一个,也是最简单的(我认为!)给新手。因此,例如:

(loop [counter 0] 
    (when (< counter 10) 
    (println counter) 
    (recur (inc counter)))) 

在这里,counter被定义为0,它永远不会改变以通常的方式。当你打recur,你提交一个新的价值,在这种情况下,增量以前counter的,进入一个全新的循环开始在loop,只是现在counter将被绑定到1

编辑:但是通知,该示例将始终返回nil。它仅用于println的副作用。为什么它会返回nil?因为在最后一次迭代中,when子句将返回nil。如果您想返回其他内容,则应该使用if并指定您希望在最后一次迭代中返回的内容。

你应该多读一点这个范例,也许可以像4clojure这样的练习来更好地掌握这个。一旦你这样做了,以这种方式思考就会变得简单多了,这种风格的巨大好处将会开始显现。

祝你好运!

0

这里是一个强力实施测试,如果他们可以通过所有号码从1分至10条件的所有数字代码(请注意(范围111)):

(first 
    (filter #(second %) 
      (map (fn[x] [x (every? identity 
            (map #(= 0 (mod x %)) 
            (range 2 11)))]) 
       (range 1 Integer/MAX_VALUE)))) 

它的输出

[2520 true] 

不幸的是,对于更大的数字,这不是一个好方法。有了(范围1 21),它在等待我的Macbook几分钟后才能完成。让我们试试这个:

user=> (defn gcd [a b] (if (zero? b) a (recur b (mod a b)))) 
#'user/gcd 
user=> (reduce (fn[acc n] (if (not= 0 (mod acc n)) (* acc (/ n (gcd n acc))) acc)) 1 (range 1 11)) 
2520  
user=> (reduce (fn[acc n] (if (not= 0 (mod acc n)) (* acc (/ n (gcd n acc))) acc)) 1 (range 1 21)) 
232792560 
+1

“#(秒%)”与简单的“秒”相同:) – Shlomi