2024 Clojure 状态调查! 中分享您的想法。

欢迎!请参阅 关于 页面了解此处的更多操作信息。

+1
序列

我在 cloth.core 中的一些地方看到了以下模式

(if (next more)
  (recur ... (next more))
  ...)

其中 `next` 在 `recur` 调用之前被调用了两次。

这是“设计”的吗,还是仅仅是未被注意到的代码?

我预期会有更高效的实现,例如

(if-let [next' (next more)]
  (recur ... next')
  ...)

3 个回答

+1
+1
by
编辑 by

这可能是在 core 中定义函数的顺序吗?

浏览 core.clj 文件时,发现 if-let 宏实际上定义在第 1841 行

https://github.com/clojure/clojure/blob/653b8465845a78ef7543e0a250078eea2d56b659/src/clj/clojure/core.clj#L1841

而 “next more recur next more” 片段(数学材料中)在使用 letif-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。

我不确定为什么顺序必须这样,可能和启动有关。

by
但 `let` 是一个特殊的表达式形式,具有 `:special-form true`,所以可能最终还是出于性能/垃圾回收的原因,就像其他回答所指出的。
0
by

我建议您使用 Criterium 库比较当前版本和修改后的函数版本的性能基准测试,看看是否能够得到更快的结果,Criterium 库用来在 Clojure/Java 上进行性能测量: https://github.com/hugoduncan/criterium

我还没有进行过这样的测量,但 HotSpot JIT 编译器有时可以做一些非常惊人的事情。

by
我同意。性能难以捉摸。

你可能也对这个类似的话题感兴趣
https://ask.clojure.org/index.php/8361/changing-some?show=8361#q8361
by
我当然在提问之前测试过了。

  (= 1 1 1 1 1 1)

在我的电脑上要快15%。
(next more)单次调用大约10纳秒。

但是不管怎样,这个问题并不是完全关于性能的。
它关于算法中不必要的重复已完成计算的重复。
...