欢迎!请参阅 关于 页面以获取更多关于如何使用本站的信息。
我在 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
而“下一个 more recur 下一个 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
我认为它与 core.clj 作为常规 Clojure 代码一样进行常规的单次遍历编译。函数必须在你可以使用它们之前进行定义,无论是宏还是 defns。
我不太确定为什么顺序必须是这样的,也许与引导有关。
我建议尝试使用当前的函数与修改后的版本之间的性能基准测试,并使用 Criterium 库在 Clojure/Java 上进行性能测量,看它是否会导致代码更快:https://github.com/hugoduncan/criterium
我还没有自己做过这样的测量,但 HotSpot JIT 编译器有时能做些非常神奇的事情。