Clojure asterisks特殊形式(fn *,let *等...)

时间:2015-09-15 21:46:10

标签: function clojure macros special-form

我发现很多"特殊形式"只是在后台使用星号版本的宏(fn *,让*和其他所有版本)。

例如,在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] ...)

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

这是出于性能原因吗?也许有人甚至可以链接到星号特殊形式的实际标准定义。

3 个答案:

答案 0 :(得分:5)

Arity选择利用JVM虚拟方法调度:each arity (from 0 to 20 arguments) has its own method,并且有21 + -arg arities的单一方法。

您可能会注意到applyTo方法,这种方法类似于您对fn&的建议。它的实现只是giant switch来选择正确的专用方法。

答案 1 :(得分:3)

是的,你可以在你提出的超原始fn&之上做所有这些宏,它肯定会简化编译器的实现。之所以没有这样做,部分是出于性能原因(它会相当缓慢,并且JVM已经有了基于arity的快速调度工具),而且部分"化妆品":这意味着每个arity都是函数是编译函数的JVM类的不同方法,这使得堆栈跟踪更好。这也有助于JIT"了解"我们的功能更好,因此可以相应地进行优化。

答案 2 :(得分:0)

我的猜测将是方便/可扩展性驱动。编译器(其中fn *实际上是“已定义”/处理过的)是用java编写的,它处理引导语言所需的最少功能,而fn是构建在它之上的宏。与其他一些形式相同。在某个地方有一个Rich的声明,他可以将编译器从java重写为clojure但是没有看到好处(如果错误则纠正我)。