欢迎!请查阅 关于 页面以了解有关此功能的一些更多信息。
我在 clojure.core 的几个地方看到了以下模式
clojure.core
(if (next more) (recur ... (next more)) ...)
其中在调用 `recur` 之前调用了两次 next。
next
这是“按设计”的,还是仅仅是未被注意到的代码?
我期望更高效一点的实现,例如
(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
而在使用“下一更再下一更”片段(数学相关)之前,并未定义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代码一样,使用core.clj进行单遍编译。你需要先定义函数,然后才能使用它们,无论是宏还是defns。
我不确定为什么顺序必须是这样的,也许与启动过程有关。
我建议您尝试使用当前版本和修改后的函数进行一些性能基准测试,并使用Criterium库对Clojure/Java进行性能测量:https://github.com/hugoduncan/criterium
我自己还没有进行过这样的测量,但HotSpot JIT编译器有时能做出相当惊人的事情。