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
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...
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
If you opt for the Haskell server process approach, you could use the MessagePack serialization/rpc library. It has bindings for both Java and Haskell , and the Haskell bindings seem to be well maintained. Look for msgpack and msgpack-rpc on Hackage.
Here's a toy example of Java/Haskell interaction using MessagePack: Java server, Haskell client (links go to GitHub). The communication is in the opposite direction of what you want, though.
It depends on how you want them to communicate. To have Java and Haskell code running natively in the same process and exchanging data in memory via their respective FFIs is a huge problem, not least because you have two GCs fighting over the data, and two compilers both of which have their own ideas about representing various data types. Getting Haskell compiled under the JVM is likewise difficult because the JVM does not (at present) have any concept of closures.
Of course these things can be done, but getting from demonstrator to industrial tool takes huge effort. My understanding is that the tools you mention never made it past the demonstrator stage.
A simpler, if less elegant, solution, is to write your Haskell program as a server process that is sent data over sockets from the Java. If performance and volume is not too high then coding it up in JSON would probably be simple, as both sides have libraries to support it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With