Clojure 星号特殊形式(fn*、let* 等...)

Clojure asterisks special forms (fn*, let*, etc...)

我发现很多 "special forms" 只是在后台使用星号版本的宏(fn*、let* 和所有其他)。

例如,在 fn 的情况下,它将解构功能添加到 fn* 单独不提供的组合中。我试图找到一些关于 fn* 自己能做什么和不能做什么的详细文档,但我没那么幸运。

绝对支持:

所以我最后的问题是,为什么不只定义:

(fn& [& all-args] ...)

这绝对是最小的,并且可以通过宏提供所有参数选择(检查参数列表的大小,if/case 语句以直接代码路径,将前几个参数绑定到所需的符号,等等)。

这是出于性能原因吗?也许有人甚至手头有 link 星号特殊形式的实际标准定义。

我的 猜测 是 convenience/extensibility 驱动的。编译器(其中 fn* 实际上是 "defined"/processed)是用 java 编写的,并处理了 bootstrap 语言所需的最少功能,而 fn 是一个构建在它。与其他一些形式相同。某处有 Rich 的声明,他可以将编译器从 java 重写为 clojure,但看不到好处(如果错误请纠正我)。

是的,您可以在您建议的超原始 fn& 之上将所有这些作为宏来完成,这肯定会简化编译器的实现。不这样做的部分原因是性能原因(它会相当慢,并且 JVM 已经具有基于 arity 的快速调度设施),部分是 "cosmetic":这意味着函数的每个 arity 是函数被编译成的 JVM class 的一种不同方法,这使得堆栈跟踪更好。这也有助于 JIT "understand" 我们的功能更好,以便它可以相应地优化。

A​​rity selection 利用 JVM 虚拟方法分派:each arity (from 0 to 20 arguments) has its own method 并且有一个方法用于 21+-arg arities。

您可能会注意到 applyTo 方法,它是类似于您建议使用 fn& 的通用方法。它的实现只是 giant switch 到 select 正确的专门方法。