Clojure 星号特殊形式(fn*、let* 等...)
Clojure asterisks special forms (fn*, let*, etc...)
我发现很多 "special forms" 只是在后台使用星号版本的宏(fn*、let* 和所有其他)。
例如,在 fn 的情况下,它将解构功能添加到 fn* 单独不提供的组合中。我试图找到一些关于 fn* 自己能做什么和不能做什么的详细文档,但我没那么幸运。
绝对支持:
&/catchall 指标
(fn* [x & rest] (do-smth-here...))
奇怪的是还有对 arity 的重载,如:
(fn* ([x] (smth-with-one-arg ...)
([x y] (smth-with-two-args ...))
所以我最后的问题是,为什么不只定义:
(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" 我们的功能更好,以便它可以相应地优化。
Arity selection 利用 JVM 虚拟方法分派:each arity (from 0 to 20 arguments) has its own method 并且有一个方法用于 21+-arg arities。
您可能会注意到 applyTo
方法,它是类似于您建议使用 fn&
的通用方法。它的实现只是 giant switch 到 select 正确的专门方法。
我发现很多 "special forms" 只是在后台使用星号版本的宏(fn*、let* 和所有其他)。
例如,在 fn 的情况下,它将解构功能添加到 fn* 单独不提供的组合中。我试图找到一些关于 fn* 自己能做什么和不能做什么的详细文档,但我没那么幸运。
绝对支持:
&/catchall 指标
(fn* [x & rest] (do-smth-here...))
奇怪的是还有对 arity 的重载,如:
(fn* ([x] (smth-with-one-arg ...) ([x y] (smth-with-two-args ...))
所以我最后的问题是,为什么不只定义:
(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" 我们的功能更好,以便它可以相应地优化。
Arity selection 利用 JVM 虚拟方法分派:each arity (from 0 to 20 arguments) has its own method 并且有一个方法用于 21+-arg arities。
您可能会注意到 applyTo
方法,它是类似于您建议使用 fn&
的通用方法。它的实现只是 giant switch 到 select 正确的专门方法。