Communication entre Java et Haskell


J'ai googlé et j'ai obtenu des réponses que la communication entre Java et Haskell peut être faite par GCJNI(maintenant le site est en panne) et LambdaVM.. Pour utiliser le LambdaVM / GCJNI, si je dois télécharger des outils de construction? Où puis-je en savoir plus sur eux, car je ne trouve pas beaucoup de ressources en ligne?

Je veux développer une application qui communique entre Java et Haskell(où je vais obtenir l'entrée de Java la passer au Haskell et y traiter et renvoyer le résultat à Java).Ce est ce que je veux faire. S'il vous plaît aider moi...

Author: Thenraja, 2012-04-29

4 answers

Appeler Haskell à partir de C semble assez facile, et peut donc également être facilement appelé à partir de Java avec JavaCPP. Par exemple, pour appeler la fonction fibonacci_hs() à partir de l'exemple de 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

Nous pouvons le faire de cette façon à partir de 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);
    }
}

Sous Linux, la procédure de compilation ressemble à ceci:

$ 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

Et le programme fonctionne normalement avec la commande habituelle java:

$ java -cp javacpp.jar:. Safe
Fibonacci: 267914296


Modifier: j'ai pris la liberté de le faire certains microbenchmarking de la surcharge appelante. Avec le fichier d'en-tête C suivant Safe.h:
inline int fibonacci_c(int n) {
    return n < 2 ? n : fibonacci_c(n - 1) + fibonacci_c(n - 2);
}

La classe Java suivante:

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");
    }
}
Il s'agit d'un processeur Intel Core i7-3632QM à 2,20 GHz, Fedora 20 x86_64, GCC 4.8.3, GHC 7.6.3 et OpenJDK 8:
fibonacci_hs(0): 200 ns
fibonacci_c(0): 9 ns
fibonacci(0): 2 ns

En toute justice, je devrais mentionner qu'il est également assez coûteux d'appeler dans la JVM...


Mise à jour: Avec les récentes modifications apportées à JavaCPP, les utilisateurs peuvent maintenant accédez à la fonction de rappel (pointeurs) par nom depuis C/C++, ce qui permet d'appeler facilement la JVM depuis Haskell. Par exemple, sur la base d'informations trouvées sur une page wiki concernant le FFI de Haskell , avec le code suivant placé dans 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

Et une fonction fibonacci définie en Java de cette façon:

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);
        }
    }
}

Nous pouvons construire sous Linux x86_64 avec quelque chose comme:

$ javac -cp javacpp.jar Main.java
$ java -jar javacpp.jar Main -header
$ ghc --make Main.hs linux-x86_64/libjniMain.so

Et le programme s'exécute correctement en donnant cette sortie:

$ ./Main
267914296
 33
Author: Samuel Audet, 2014-12-06 03:10:08

Si vous optez pour l'approche Haskell server process, vous pouvez utiliser la bibliothèque MessagePack serialization/rpc. Il a des liaisons pour Java et Haskell , et les liaisons Haskell semblent être bien maintenues. Recherchez msgpack et msgpack-rpc sur Hackage.

Voici un exemple jouet d'interaction Java/Haskell utilisant MessagePack: Java server, Le client Haskell (les liens vont à GitHub). La communication est dans le sens opposé de ce que vous voulez, bien que.

 6
Author: danidiaz, 2012-04-29 15:33:40

Cela dépend de la façon dont vous voulez qu'ils communiquent. Avoir du code Java et Haskell en cours d'exécution nativement dans le même processus et échanger des données en mémoire via leurs FFI respectifs est un énorme problème, notamment parce que vous avez deux GCs qui se disputent les données, et deux compilateurs qui ont leurs propres idées sur la représentation de différents types de données. Obtenir Haskell compilé sous la JVM est également difficile car la JVM n'a pas (à l'heure actuelle) de concept de fermetures.

Bien sûr ces choses peuvent être faites, mais passer du démonstrateur à l'outil industriel demande un effort énorme. Je crois comprendre que les outils que vous mentionnez n'ont jamais dépassé le stade du démonstrateur.

Une solution plus simple, bien que moins élégante, consiste à écrire votre programme Haskell en tant que processus serveur qui envoie des données sur des sockets à partir de Java. Si les performances et le volume ne sont pas trop élevés, le codage dans JSON serait probablement simple, car les deux parties ont des bibliothèques pour le prendre en charge.

 3
Author: Paul Johnson, 2012-04-29 08:49:41

TL; DR: Utilisez le modèle de transmission de message (c'est-à-dire RPC client-serveur ou pairs).

Pourquoi? C'est plus sûr, évolutif, flexible et débogable. L'appel à FFI va être fragile et difficile à tester.


Cadres/spécifications RPC

  • GRPC Le fork public de Google de Protobufs RPC sur HTTP / 2

  • Msgpack-rpc Ne comprend pas de transport.

  • Zerorpc ZeroMQ + msgpack. N'a que des implémentations Python et Node. Semble abandonné aussi.

  • XML-RPC Matures. interopérabilité large mais c'est aussi XML.

  • JSON-RPC plus Facile à déboguer. Pas un protocole binaire, bien que BSON puisse pirater certaines bibliothèques.


La Sérialisation

  • Tampons de protocole (protobufs) Il y a beaucoup, beaucoup plus d'outils pour elle que d'autres. Il prend en charge les membres de données versionnés/facultatifs qui n'ont pas besoin de recompiler (ou de casser) le monde pour interopérer.

  • Msgpack Mignon, simple et efficace, mais il ne prend pas en charge les modifications de schéma compatibles avec l'avant. C'est purement un codec binaire stupide. Probablement trop simple et de bas niveau pour une utilisation pratique.


Transporte

  • ZeroMQ Probablement le plus rapide, non Infiniband/FC/10 GbE, non thread-safe transport des messages.

  • Nanomsg Un nouveau, thread-safe, philosophie UNIX réimaginer de ZeroMQ de l'un de ses fondateurs.

  • HTTP / 2 (utilisé par gRPC) L'avantage ici est que c'est une norme qui fonctionne à l'intérieur et entre les centres de données, et a également TLS (le code natif gRPC utilise BoringSSL, le fork OpenSSL "plus sécurisé" de Google).

  • MQTT Lorsque vous avez besoin pour mettre en œuvre pousser notifications à un milliard d'appareils et utiliser un protocole lisible par l'homme.

 0
Author: Barry, 2017-03-22 03:14:37