【问题标题】:How to avoid calling a function twice in (recur ..)如何避免在 (recur ..) 中调用函数两次
【发布时间】:2014-01-03 11:43:27
【问题描述】:

请考虑这段代码。

(loop [k from res '()]
    (if (< (count res) n)
      (recur (next-num k)  (conj res (next-num k)))
      (sort res)))

现在,假设函数(next-num k) 进行一些昂贵的计算。我们不能打电话两次。什么是替代方案?我是 Clojure 的新手,不知道很多基本功能。但我相信一定有办法。

【问题讨论】:

    标签: loops clojure tail-recursion


    【解决方案1】:

    使用let:

    (loop [k from res '()]
        (if (< (count res) n)
          (let [the-next-num (next-num k)]
              (recur the-next-num  (conj res the-next-num)))
          (sort res)))
    

    【讨论】:

    • 或者,完全避免循环:(-&gt;&gt; (iterate next-num from) rest (take n) sort)
    • @Beyamor:你的建议很有魅力。但我不知道为什么。请您详细说明一下,可能在您的单独答案中。
    • 我取消了我的答案并解释了无环代码,但@Nathan 在使用let 时绝对击败了我。
    【解决方案2】:

    就像@NathanDavis 所说,let 允许您命名中间值:

    (loop [k from res '()]
      (if (< (count res) n)
        (let [next-k (next-num k)]
          (recur next-k (conj res next-k)))
        (sort res)))
    

    但是,在获得loop 之前,值得看看您是否可以将核心功能组合成相同的效果。通常,您可以编写一些不太复杂的东西并公开重要的细节。

    代码的核心是建立一系列next-num 的重复应用程序。幸运的是,有一个核心函数可以做到这一点:iterate。使用iterate,我们可以创建一个无限的惰性值序列:

    (iterate next-num from)
    ; => (from, from', from'', ...)
    

    但是,我们不想要这些值中的第一个。我们可以通过rest 获得序列的其余部分:

    (rest
      (iterate next-num from))
    ; => (from', from'', from''', ...)
    

    此时,我们可以用take获取n的值:

    (take n
      (rest
        (iterate next-num from)))
    ; => (from', from'', from''')
    

    最后,我们可以对这些n 值进行排序:

    (sort
      (take n
        (rest
          (iterate next-num from))))
     ; => (from'', from', from''')
    

    当然,深度嵌套的函数调用很快就会变得尴尬。线程宏-&gt;&gt;(就像它的兄弟-&gt;)是一种语法糖,可以让我们将代码重新排列成更好的东西:

    (->>
      (iterate next-num from)
      rest
      (take n)
      sort)
    

    因此,您可以看到强大的序列操作函数库如何让我们摆脱低级循环。

    【讨论】:

    • 确实是一个很棒的解释。虽然,我已经接受了另一个答案,因为let 实际上并且准确地说是我的问题的答案。但这种方法绝对更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-14
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 2021-05-16
    • 1970-01-01
    • 2021-10-09
    相关资源
    最近更新 更多