假设我有以下 Clojure 代码:
(defn foo ^double []
  (- 
    (* 123.31
     (+ 4 5 6 (Math/sin 34.2))
     123.31) 
    123))
gen-class 会产生相当于编译以下 java 代码的字节码:
public static double foo(){
   return (123.31 * (4 + 5 + 6 + Math.sin(34.2)) * 123.31) - 123;
}
或者换句话说,我可以使用 Clojure 作为一种非常方便的 DSL 来生成高效的动态字节码吗?
编辑:
好的,我做了一些测试来说明我的问题:
这是java版本:
public class FooTest {
  public static double foo(double a, double b, double c){
    return (a * (b + c + (b*c) + Math.sin(a)) * Math.log(b)) - b;
  }
  public static long benchmark(){
    long start = System.currentTimeMillis();
    for (double i = 0; i < 100000000.0; i++) { // 100 mln
      double r = foo(i, i+1, i+2);
    }
    long end = System.currentTimeMillis();
    return (end-start);
  }
  public static void main(String[] args) {
    System.out.println("Time took: "+benchmark());
  }
}
这会产生输出:耗时:39200
clojure“等效”:
(defn foo ^double 
  (^double [a b c]
  (- 
    (* a
     (+ b c (* b c) (Math/sin a))
     (Math/log b)) 
    b)))
(time
  (loop [i 0.0] 
    (when (< i 100000000)   
      (foo i (+ i 1) (+ i 2))
      (recur (inc i)))))
这会产生:“经过的时间:121242.902 毫秒”
这慢了 3 倍。
现在我改写的问题是:我如何构造/提示 clojure 代码,以便避免代码中的函数调用,这实际上是原始数学运算?
编辑2:
我更改了测试,因此它使用未经检查的原始数学运算符:
(defn foo ^double 
  (^double [a b c]
  (binding [*unchecked-math* true] 
    (- 
      (* a
       (+ b c (* b c) (Math/sin a))
       (Math/log b)) 
      b))))
“经过的时间:64386.187 毫秒”所以它几乎是 Java 版本的 2 倍,但仍然是 Java 版本的 1.6 倍。