欢迎!请查看 关于 页面,了解更多关于这个网站的信息。
我在 clojure.core 的几个位置看到以下模式
clojure.core
(if (next more) (recur ... (next more)) ...)
其中在调用 `recur` 之前,`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
我认为这应该与 core.clj 的常规单遍编译有关,就像常规的 Clojure 代码一样。函数必须在您可以使用它们之前进行定义,包括宏和 defns。
我不确定为什么顺序必须这样,可能和启动有关。
:special-form true
我建议尝试使用 Criterium 库对您正在考虑的当前版本和修改后的函数进行性能基准测试,并查看它是否会使代码更快:https://github.com/hugoduncan/criterium
我自己没有进行过这类测试,但 HotSpot JIT 编译器有时能做些很神奇的事情。