欢迎!请查看 关于 页面以了解该服务的更多信息。
我在 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 行定义的
https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/clj/clojure/core.clj#L1841
而在数学内容中的"下一更多的递归下一更多的"片段(在 `let` 或 `if-let` 存在之前)被使用(第 1055 行)
https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/clj/clojure/core.clj#L1055
`defmacro if-let` 之后的代码实际上使用的是你期望的模式(第 3690 行)
https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/clj/clojure/core.clj#L3690
我认为这应该是一个常规的单次遍历编译,就像是常规的 Clojure 代码一样。函数必须在使用前定义,无论是宏还是 defns。
我不确定为什么顺序必须这样,可能和启动过程有关。
我建议尝试与当前修改版本的函数进行一些性能基准测试,看看它是否会导致代码运行更快,使用 Criterium 库在 Clojure/Java 上进行性能测量: https://github.com/hugoduncan/criterium
我本人没有做过此类测量,但 HotSpot JIT 编译器有时能做些令人惊奇的事情。