欢迎!请参阅关于页面,了解这份工作的一些更多信息。
我在《clojure.core》的几个地方看到了以下的模式
(if (next more) (recur ... (next more)) ...)
其中调用了两次 `next` 然后 `recur`。
这是“按设计”还是仅仅是未被注意到的代码?
我希望有更高效的实现,如下
(if-let [next' (next more)] (recur ... next') ...)
可能是为了避免持有序列的“头部”的风险。一般来说,希望在递归调用之前,序列的已经消费部分可以被垃圾回收。
这是否是Core中函数定义的顺序?
在查看core.clj时,发现if-let宏实际上是在第1841行定义的
if-let
https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/clj/clojure/core.clj#L1841
但是“下一个更多recur下一个更多”(在数学素材中)是在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编译器有时可以做些令人惊讶的事情。