将Java代码转换为快速的Clojure代码

时间:2010-09-27 20:24:50

标签: clojure

这个Java代码是否可以转换为快速或接近快速的Clojure代码?

我已经能够获得更简单的功能,比如添加两个数组,以合理的速度运行类型提示,但是我无法让Clojure使用Java在合理的时间内完成以下函数的操作interop或Incanter矩阵并使用功能或命令式样式。

我是否遗漏了关于类型提示的内容,或者最好是用Java做这种事情?

static double[][] grad2_stencil= { {0,0,-1,0,0}, 
                             {0,0,16,0,0}, 
                             {-1,16,-60,16,-1}, 
                             {0,0,16,0,0}, 
                             {0,0,-1,0,0} };

public static double grad2(double[][] array, int x, int y){
    double temp=0;
    int L=array.length;
    for(int i=0; i<5; i++){
        for(int j=0; j<5; j++){
            temp+=array[((x+i-2)%L+L)%L][((y+j-2)%L+L)%L]*grad2_stencil[i][j];
        }
    }
    return temp/12.0;
}

public static double[][] grad2_field(double[][] arr){
    int L=arr.length;
    double[][] result=new double[L][L];

    for(int i=0; i<L; i++){
        for(int j=0; j<L; j++){
            result[i][j]=grad2(arr, i, j);
        }
    }

    return result;
}

3 个答案:

答案 0 :(得分:8)

在clojure 1.3(主分支)中尝试以下内容:

(def ^"[[D" grad2-stencil
  (into-array (Class/forName "[D")
    (map double-array 
      [[ 0   0  -1  0  0 ] 
       [ 0   0  16  0  0 ]
       [-1  16 -60 16 -1 ] 
       [ 0   0  16  0  0 ] 
       [ 0   0  -1  0  0 ]])))

(defn ^:static idx ^long [^long x ^long i ^long L]
  (-> x
    (+ i)
    (- 2)
    (mod L)
    (+ L)
    (mod L)))

(defn ^:static grad2 ^double [^doubles arr ^long x ^long y]
  (let [L (alength arr)
        temp (loop [i 0 j 0 temp 0.0]
               (if (< i 5) 
                 (let [a (idx x i L)
                       b (idx y j L)
                       temp (double (* (aget arr a b) 
                                      (aget grad2-stencil i j)))]
                   (if (< j 4)
                     (recur i (inc j) temp)
                     (recur (inc i) 0 temp)))
                 temp))]
    (/ temp 12.0)))

(defn ^:static grad2-field ^"[[D" [^"[[D" arr]
  (let [result (make-array Double/TYPE (alength arr) (alength arr))]
    (loop [i 0 j 0]
      (when (< i 5)
        (aset result (grad2 arr i j) i j)
        (if (< j 4)
          (recur i (inc j))
          (recur (inc i) 0))))
    result))

答案 1 :(得分:5)

从当前在github上的clojure 1.3分支开始,您可以use primitives as arguments to functions并从函数返回。您也将不再需要键入提示编号基元。它应该能够更快地暗示这种类型的代码并且看起来更优雅。

在类型提示中,你可能会遇到(&lt; = clojure 1.2)所有函数参数被装箱的事实。

答案 2 :(得分:3)

另一个有帮助的部分(也在1.3中)是静态函数链接,这将使一些函数调用与方法调用一样快(这也在Arthur发布的链接中描述)。

现在仍然很难以真正惯用的方式编写此代码(即使用“map”高阶函数),因为高阶函数将无法使用静态链接,但是(无耻的插头警告)这是Rich Hickey想要纠正的事情:

http://combinate.us/clojure/2010/09/27/clojure/