如何避免两次调用函数(重复..)

Ade*_*ari 1 loops tail-recursion clojure

请考虑这段代码.

(loop [k from res '()]
    (if (< (count res) n)
      (recur (next-num k)  (conj res (next-num k)))
      (sort res)))
Run Code Online (Sandbox Code Playgroud)

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

Nat*_*vis 5

用途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)))
Run Code Online (Sandbox Code Playgroud)

  • 或者,完全避免循环:`( - >>(迭代next-num from)rest(取n)sort)` (4认同)

Bey*_*mor 5

就像@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)))
Run Code Online (Sandbox Code Playgroud)

但是,在达到a之前loop,值得看看你是否可以将核心功能组合成相同的效果.通常,您可以编写不那么复杂的内容并公开重要的细节.

代码的内容涉及构建一系列重复应用程序next-num.幸运的是,有一个核心功能可以做到这一点:iterate.使用iterate,我们可以创建一个无限懒惰的值序列:

(iterate next-num from)
; => (from, from', from'', ...)
Run Code Online (Sandbox Code Playgroud)

但是,我们不希望这些值中的第一个.我们可以通过以下方式获得序列的其余部分rest:

(rest
  (iterate next-num from))
; => (from', from'', from''', ...)
Run Code Online (Sandbox Code Playgroud)

此时,我们可以通过以下方式获取ntake:

(take n
  (rest
    (iterate next-num from)))
; => (from', from'', from''')
Run Code Online (Sandbox Code Playgroud)

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

(sort
  (take n
    (rest
      (iterate next-num from))))
 ; => (from'', from', from''')
Run Code Online (Sandbox Code Playgroud)

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

(->>
  (iterate next-num from)
  rest
  (take n)
  sort)
Run Code Online (Sandbox Code Playgroud)

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