欢迎!请查看 关于 页面以获取更多关于如何使用本站的信息。
我在 clojure.core 的几个地方看到了以下模式
clojure.core
(if (next more) (recur ... (next more)) ...)
其中 next 调用两次,在 recur 之前。
next
recur
这是否是“故意为之”还是未注意到的代码?
我期望有一个更高效的实现,比如:
(if-let [next' (next more)] (recur ... next') ...)
这可能是为了避免“抓住序列的头部”的风险。通常,你希望在递归调用之前,序列已被消费的部分可由垃圾收集器回收。
这可能是核心中函数定义的顺序问题吗?
浏览core.clj文件时,if-let 宏实际上定义在第1841行
if-let
https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/clj/clojure/core.clj#L1841
而“next more recur next more”片段(在数学内容中)在let或if-let存在之前就已经使用(第1055行)
let
https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/clj/clojure/core.clj#L1055
defmacro if-let之后的代码实际上使用了您预期的模式(第3690行)
defmacro if-let
https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/clj/clojure/core.clj#L3690
我认为这应该像是常规的单遍编译,与常规的Clojure代码类似,函数必须在使用之前定义,无论是宏还是defns。
我不确定为什么顺序要这样,可能和引导(bootstrapping)有关。
我建议使用Criterium库尝试一些性能基准测试,以比较您要修改的函数当前和修改后的版本,并查看它是否会导致代码运行更快:https://github.com/hugoduncan/criterium
我还没有自己进行过这样的测量,但HotSpot JIT编译器有时能做一些相当惊人的事情。