Java和Haskell之间的通信 [英] Communication between Java and Haskell
问题描述
我搜索了一些答案,可以通过GCJNI(现在网站已关闭)和LambdaVM完成Java与Haskell之间的通信。要使用LambdaVM / GCJNI,是否需要下载任何构建工具?我在哪里可以了解更多关于他们的信息,因为我没有在网上找到很多资源?
我想开发一个在Java和Haskell之间进行通信的应用程序(我将从Java的输入中将其传递给Haskell并在那里处理并返回结果Java)。这是我想要做的。请帮助我...
从C调用Haskell看起来很容易,因此也可以通过 JavaCPP 的。例如,要从示例代码 Safe.hs
中调用 fibonacci_hs()
函数:
{ - #LANGUAGE ForeignFunctionInterface# - }
模块安全其中
导入Foreign.C。类型
fibonacci :: Int - > Int
fibonacci n = fibs !! n
其中fibs = 0:1:zipWith(+)fibs(尾纤)
fibonacci_hs :: CInt - > CInt
fibonacci_hs = fromIntegral。斐波纳契。 fromIntegral
国外出口ccall fibonacci_hs :: CInt - > CInt
我们可以用Java这种方式完成它:
import org.bytedeco.javacpp。*;
import org.bytedeco.javacpp.annotation。*;
@Platform(include = {< HsFFI.h>,Safe_stub.h})
public class Safe {
static {Loader.load(); }
public static native void hs_init(int [] argc,@Cast(char ***)@ByPtrPtr PointerPointer argv);
public static native int fibonacci_hs(int i);
public static void main(String [] args){
hs_init(null,null);
int i = fibonacci_hs(42);
System.out.println(Fibonacci:+ i);
$ / code>
在Linux下,编译过程如下所示: / p>
$ ghc -fPIC -dynamic -c -O Safe.hs
$ javac -cp javacpp.jar Safe.java
$ java -jar javacpp.jar -Dplatform.compiler = ghc -Dplatform.compiler.output = - optc-O3 -Wall Safe.o -dynamic -fPIC -shared -lstdc ++ -lHSrts-ghc7.6.3 -o -Dplatform.linkpath.prefix2 = - optl -Wl,-rpath,Safe
程序通常使用通常的 java
命令运行:
$ java -cp javacpp.jar :. Safe
Fibonacci:267914296
编辑 strong>:我冒昧地做了一些调用开销的微观基准。使用以下C头文件
Safe.h
: inline int fibonacci_c (int n){
return n< 2? n:fibonacci_c(n - 1)+ fibonacci_c(n - 2);
}
以下Java类:
import org.bytedeco.javacpp。*;
import org.bytedeco.javacpp.annotation。*;
$ b @Platform(include = {< HsFFI.h>,Safe_stub.h,Safe.h})
public class Safe {
static { Loader.load方法(); }
public static native void hs_init(int [] argc,@Cast(char ***)@ByPtrPtr PointerPointer argv);
public static native int fibonacci_hs(int i);
public static native int fibonacci_c(int n);
public static int fibonacci(int n){
return n< 2? n:斐波纳契(n - 1)+斐波纳契(n - 2);
}
public static void main(String [] args){
hs_init(null,null);
for(int i = 0; i <1000000; i ++){
fibonacci_hs(0);
fibonacci_c(0);
fibonacci(0);
}
long t1 = System.nanoTime();
for(int i = 0; i< 1000000; i ++){
fibonacci_hs(0);
}
long t2 = System.nanoTime();
for(int i = 0; i< 1000000; i ++){
fibonacci_c(0);
}
long t3 = System.nanoTime();
for(int i = 0; i< 1000000; i ++){
fibonacci(0);
}
long t4 = System.nanoTime();
System.out.println(fibonacci_hs(0):+(t2 - t1)/ 1000000 +ns);
System.out.println(fibonacci_c(0):+(t3 - t2)/ 1000000 +ns);
System.out.println(fibonacci(0):+(t4 - t3)/ 1000000 +ns);
}
}
用Intel Core i7-3632QM CPU @ 2.20GHz,Fedora 20 x86_64,GCC 4.8.3,GHC 7.6.3和OpenJDK 8:
fibonacci_hs(0): 200 ns
fibonacci_c(0):9 ns
fibonacci(0):2 ns
平心而论,我应该提到将调用到 JVM也是相当昂贵的...
更新:最近对JavaCPP进行的更改用户现在可以通过C / C ++中的名称访问回调函数(指针),从而可以轻松地从Haskell调用JVM。例如,根据 wiki页面上有关Haskell的FFI 的信息,并将下列代码放入
Main.hs
: { - #LANGUAGE ForeignFunctionInterface# - }
模块Main其中
导入Foreign.C - 获取C类型
导入Foreign.Ptr(Ptr,nullPtr)
- 不纯函数
foreign import ccallJavaCPP_initc_javacpp_init :: CInt - > Ptr(Ptr CString) - > IO()
javacpp_init :: IO()
javacpp_init = c_javacpp_init 0 nullPtr
- 纯函数
外部导入ccallfibonaccic_fibonacci :: CInt - > ; CInt
fibonacci :: Int - > Int
fibonacci i = fromIntegral(c_fibonacci(fromIntegral i))
main = do
javacpp_init
print $ fibonacci 42
和Java中这样定义的 fibonacci
函数:
import org.bytedeco.javacpp。*;
import org.bytedeco.javacpp.annotation。*;
@Platform
public class Main {
public static class Fibonacci extends FunctionPointer {
public @Name(fibonacci)int call(int n){
return n < 2? n:通话(n - 1)+通话(n - 2);
$ / code $ / pre
我们可能在Linux x86_64下构建类似于:
$ javac -cp javacpp.jar Main.java
$ java -jar javacpp.jar Main -header
$ ghc --make Main.hs linux-x86_64 / libjniMain.so
并且程序正确地执行这个输出:
$ ./Main
267914296
I googled and got some answers that communication between Java and Haskell can be done by GCJNI(Now the site is down) and LambdaVM.. To use the LambdaVM/GCJNI, whether I need to download any build tools? Where can I know more about them, since I don't find much resources on online?
I want to develop an application that communicates between Java and Haskell(Where I will get the input from Java pass it to the Haskell and process there and return the result back to Java).This is what I want to do. Please help me...
解决方案 Calling Haskell from C appears quite easy, and thus can also be easily called from Java with JavaCPP. For example, to call the fibonacci_hs()
function from the sample code Safe.hs
:
{-# LANGUAGE ForeignFunctionInterface #-}
module Safe where
import Foreign.C.Types
fibonacci :: Int -> Int
fibonacci n = fibs !! n
where fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
fibonacci_hs :: CInt -> CInt
fibonacci_hs = fromIntegral . fibonacci . fromIntegral
foreign export ccall fibonacci_hs :: CInt -> CInt
we can do it this way from Java:
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
@Platform(include={"<HsFFI.h>","Safe_stub.h"})
public class Safe {
static { Loader.load(); }
public static native void hs_init(int[] argc, @Cast("char***") @ByPtrPtr PointerPointer argv);
public static native int fibonacci_hs(int i);
public static void main(String[] args) {
hs_init(null, null);
int i = fibonacci_hs(42);
System.out.println("Fibonacci: " + i);
}
}
Under Linux, the compilation procedure looks like this:
$ ghc -fPIC -dynamic -c -O Safe.hs
$ javac -cp javacpp.jar Safe.java
$ java -jar javacpp.jar -Dplatform.compiler=ghc -Dplatform.compiler.output="-optc-O3 -Wall Safe.o -dynamic -fPIC -shared -lstdc++ -lHSrts-ghc7.6.3 -o " -Dplatform.linkpath.prefix2="-optl -Wl,-rpath," Safe
And the program runs normally with the usual java
command:
$ java -cp javacpp.jar:. Safe
Fibonacci: 267914296
Edit: I have taken the liberty to do some microbenchmarking of the calling overhead. With the following C header file Safe.h
:inline int fibonacci_c(int n) {
return n < 2 ? n : fibonacci_c(n - 1) + fibonacci_c(n - 2);
}
the following Java class:
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
@Platform(include={"<HsFFI.h>","Safe_stub.h", "Safe.h"})
public class Safe {
static { Loader.load(); }
public static native void hs_init(int[] argc, @Cast("char***") @ByPtrPtr PointerPointer argv);
public static native int fibonacci_hs(int i);
public static native int fibonacci_c(int n);
public static int fibonacci(int n) {
return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}
public static void main(String[] args) {
hs_init(null, null);
for (int i = 0; i < 1000000; i++) {
fibonacci_hs(0);
fibonacci_c(0);
fibonacci(0);
}
long t1 = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
fibonacci_hs(0);
}
long t2 = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
fibonacci_c(0);
}
long t3 = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
fibonacci(0);
}
long t4 = System.nanoTime();
System.out.println("fibonacci_hs(0): " + (t2 - t1)/1000000 + " ns");
System.out.println("fibonacci_c(0): " + (t3 - t2)/1000000 + " ns");
System.out.println("fibonacci(0): " + (t4 - t3)/1000000 + " ns");
}
}
outputs this with an Intel Core i7-3632QM CPU @ 2.20GHz, Fedora 20 x86_64, GCC 4.8.3, GHC 7.6.3, and OpenJDK 8:
fibonacci_hs(0): 200 ns
fibonacci_c(0): 9 ns
fibonacci(0): 2 ns
In all fairness, I should mention that it is also pretty expensive to call into the JVM as well...
Update: With recent changes to JavaCPP, users can now access callback function (pointers) by name from C/C++, making it possible to call into the JVM from Haskell easily. For example, based on information found on a wiki page regarding Haskell's FFI, with the following code placed in Main.hs
:{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
import Foreign.C -- get the C types
import Foreign.Ptr (Ptr,nullPtr)
-- impure function
foreign import ccall "JavaCPP_init" c_javacpp_init :: CInt -> Ptr (Ptr CString) -> IO ()
javacpp_init :: IO ()
javacpp_init = c_javacpp_init 0 nullPtr
-- pure function
foreign import ccall "fibonacci" c_fibonacci :: CInt -> CInt
fibonacci :: Int -> Int
fibonacci i = fromIntegral (c_fibonacci (fromIntegral i))
main = do
javacpp_init
print $ fibonacci 42
and a fibonacci
function defined in Java this way:
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
@Platform
public class Main {
public static class Fibonacci extends FunctionPointer {
public @Name("fibonacci") int call(int n) {
return n < 2 ? n : call(n - 1) + call(n - 2);
}
}
}
we may build under Linux x86_64 with something like:
$ javac -cp javacpp.jar Main.java
$ java -jar javacpp.jar Main -header
$ ghc --make Main.hs linux-x86_64/libjniMain.so
and the program executes correctly giving this output:
$ ./Main
267914296
这篇关于Java和Haskell之间的通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!