java在clojure中动态生成高性能函数
我正在尝试使用Clojure动态生成可应用于大量数据的函数,也就是说,要求将函数编译为字节码,以便快速执行,但直到运行时才知道它们的规范
例如,假设我用一个简单的DSL指定函数,比如:
(def my-spec [:add [:multiply 2 :param0] 3])
我想创建一个函数编译规范,以便:
(compile-spec my-spec)
将返回一个参数x的编译函数,该参数x返回2x+3
在Clojure做这件事的最佳方式是什么
# 1 楼答案
即使你没有编译你的代码,一旦你定义了一个函数,它就会被编译成字节码
# 2 楼答案
Hamza Yerlikaya已经提出了最重要的一点,那就是Clojure代码总是编译的。我只是添加了一个插图和一些关于一些低挂果实的信息,以供您进行优化
首先,关于Clojure的代码总是被编译的这一点,包括由高阶函数返回的闭包,以及通过调用
fn
/fn*
形式上的eval
创建的函数,以及实际上可以充当Clojure函数的任何其他函数。因此,不需要单独的DSL来描述函数,只需使用高阶函数(可能还有宏):如果您的规范中包含有关参数类型的信息,那么事情会更有趣,因为您可能会对编写宏来使用这些类型提示生成代码感兴趣。我能想到的最简单的例子是上面的一个变体:
使用
:int
、:long
、:float
或:double
(或相应名称的非命名空间限定符号)作为第一个参数,以利用适合于参数类型的未装箱原语算术。这可能会给你带来非常显著的性能提升,具体取决于你的函数在做什么其他类型的提示通常使用
#^Foo bar
语法(^Foo bar
在1.2中做同样的事情);如果要将它们添加到宏生成的代码中,请研究with-meta
函数(需要将'{:tag Foo}
合并到表示函数的形式参数的符号元数据中,或let
引入的局部变量中,以便对其进行类型提示)如果你还想知道如何实现你最初的想法
您总是可以构造Clojure表达式来定义函数
(list 'fn ['x] (a-magic-function-to-generate-some-code some-args ...))
,并对结果调用eval
。这将使您能够执行以下操作(要求规范包含参数列表会更简单,但这里有一个版本,假设参数是从规范中提取出来的,所有参数都被称为paramFOO
,并按字典顺序排序):绝大多数情况下,这样做没有充分的理由,应该避免;改用高阶函数和宏。然而,如果你正在做一些事情,比如说,进化编程,那么它就在那里,提供了终极的灵活性,结果仍然是一个编译函数