【问题标题】:function recursion in clojureclojure 中的函数递归
【发布时间】:2016-11-10 19:52:15
【问题描述】:

我正在处理 clojure 中的递归,我不太明白。 我做了一个取自here 的小程序,它试图找到可以除以1 到20 的所有数字的小数。这是我写的代码,但一定有一些东西我丢失了,因为它不起作用。 你能帮我一把吗?谢谢!

(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

【问题讨论】:

  • 投资于理解循环/递归、不变性和标准库序列转换函数 - while 是一种命令式循环结构,根据我的经验,每年使用的次数不会超过一次或两次。
  • 看来您是在黑暗中拍摄。例如,您认为(index 20) 会做什么?此外,在recur 中,值的顺序很重要,我不确定您是否按照自己的想法行事。
  • 我刚刚编辑了关于订单的问题。我对(index 20) 的意思是再次将索引设置为20。 @shlomi
  • @Capie,所以这不是它在做什么。事实上,它会抛出一个错误,因为index 不是一个函数,而你正试图将20 应用于函数index。如果你想保持index 为 20,你应该简单地做(recur (inc nume) 20)。此评论也适用于(nume),您正在尝试调用该号码:)。我更新了我的答案,看看这是否有帮助。
  • @shlomi 帮了大忙。它的工作。谢谢老兄。

标签: recursion clojure


【解决方案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 之类的练习以更好地掌握这一点。一旦你这样做了,你用这种方式思考就会变得简单得多,这种风格的巨大好处将开始显现。

祝你好运!

【讨论】:

    【解决方案2】:

    这是一个蛮力实现测试所有数字是否可以除以代码中从 1 到 10 的所有数字(请注意(范围 1 11)):

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

    它的输出是

    [2520 true]
    

    不幸的是,这不是处理更大数字的好方法。使用 (range 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
    

    【讨论】:

    • #(second %) 等同于简单的second :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-20
    • 1970-01-01
    • 2011-08-03
    • 2012-02-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多