欢迎!有关如何使用本站点的一些更多信息,请查看关于 页面。
我在 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
而“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
我认为这应该与 core.clj 作为常规 Clojure 代码的常规单次编译相同。必须先定义函数,然后才能使用,无论是宏还是 defns。
我不确定为什么顺序必须是这样的,可能和启动过程有关。
我建议尝试使用 Criterium 库(对 Clojure/Java 进行性能测量的库)对当前版本与修改后的函数版本进行一些性能基准测试,看看是否会提高代码的执行速度: https://github.com/hugoduncan/criterium
我还没有亲自做过这样的测量,但是 HotSpot JIT 编译器有时能做些很棒的事情。