请考虑这段代码。
(loop [k from res '()]
(if (< (count res) n)
(recur (next-num k) (conj res (next-num k)))
(sort res)))
现在,假设函数(next-num k)
做了一些昂贵的计算。我们不能两次打电话。替代方案是什么?我是Clojure的新手,并不知道很多基本功能。但我相信一定有办法。
答案 0 :(得分: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)))
答案 1 :(得分: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)))
然而,在达到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''')
当然,深度嵌套函数调用很快就会变得尴尬。线程宏->>
(就像它的兄弟->
)是一些语法糖,让我们可以将代码重新排列成更好的代码:
(->>
(iterate next-num from)
rest
(take n)
sort)
所以,你可以看到强大的序列操作函数库如何让我们摆脱低级循环。