views:

1029

answers:

6

Since both ruby and Haskell supports FFI,

  • Is it possible to call Haskell code from ruby, may be through FFI ?
  • Is there any Haskell binding in Ruby ?
+5  A: 

I haven't seen it done before, but it's possible.

  • Use Haskell's FFI to wrap libruby. Your main executable will be written in Haskell, which will call ruby_init() and related functions, in order to run the Ruby interpreter in-process. This does allow you to run arbitrary Ruby code, though.
  • Use Ruby's FFI to wrap a GHC module as a library. Your Ruby script must call hs_init(), and can only access foreign exported functions.

You'll need to write glue code, some in C, to get either of those two options working.

  • Run Ruby and Haskell in separate processes, using some IPC to communicate between them. Maybe XML-RPC (Haskell/Ruby), or JSON (Haskell/Ruby) over sockets, or maybe even just pipes with your own custom protocol.

I don't know what your requirements are, but this is what I'd go for -- it's a lot easier.

ephemient
A: 

@ephemient, I am actually looking for someways to use Ruby (high level + dynamic) to be the main controller logic and invoking haskell for large amount of data crunching (functional + speed)

I think native binding is close to non-existence, apart from this tweet http://twitter.com/BlurredWeasel/status/1321484127

Using JSON RPC will be probably the easiest way to implement where there is a thin wrapper in ruby to (method_missing) to invoke haskell over JSON/Socket.

JSON has the advantage of being able to easily map primitives to native types between various languages..

class SciHs
  def method_missing(method, *args) 
     // json encode
     // request Haskell over tcp socket or unix pipes
     // json decode
  end
end

Other alternative for fast number crunching in ruby (+ functional style)

  • NArray or other scientific library in ruby
  • Ruby binding of GNU Scientific Library
  • or go ruby 1.9 and use YARV2LLVM to JIT the calculation logic into LLVM for faster execution.

Thoughts anyone?

JSON is easy to deal with in Haskell; I have an implementation of aJSON-based wire-protocol here: http://github.com/jrockway/app-persistent/blob/905f90b16a536baa09082b9083185f16323c51b5/client/App/Persistent/Client/Message.hs
jrockway
+1  A: 

I am not sure about the Haskell side, but here is a cool video from Mountain West Ruby Conf 09 about working with FFI from Ruby. It looks like a pretty nice interface.

http://mwrc2009.confreaks.com/13-mar-2009-16-10-ffi-jeremy-hinegardner.html

danmayer
A: 

I tried exactly this (I'm the one from the mentioned tweet).

I didn't think of the libruby approach, but I spent a fair amount trying to use ruby's FFI to wrap an exported function from haskell, and could never quite get it to all link and run.

If you look at haskell's FFI examples, you'll see that they all include a C main() function. Since ruby's FFI doesn't have (and can't have) a main(), that won't work. If you try without that, you end up with weird link errors.

I can share what I have with you, ping me on freenode (cschneid), or on twitter (BlurredWeasel).

+6  A: 

I'm a bit late to this discussion, but I'm currently writing a bridge between Ruby and Haskell. It's at http://github.com/mwotton/Hubris - it's a binding that works at the C level. Still at a very early stage of development, though.

Mark Wotton
+2  A: 

GHC 6.12.1 supports building dynamic libraries on Linux. Try something like:

Example.hs

{-# LANGUAGE ForeignFunctionInterface #-}

module Example 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

wrapper.c

#include <stdlib.h>

#include "HsFFI.h"

void
example_init (void)
{
  hs_init (NULL, NULL);
}

void
example_exit (void)
{
  hs_exit ();
}

script.rb

require 'dl'
require 'dl/import'

module Example
    extend DL::Importable
    dlload "./libffi-example.so"
    extern "void example_init()"
    extern "void example_exit()"
    extern "int fibonacci_hs(int)"
end

Example.example_init

1.upto( 40 ) do | x |
    puts "#{ x } -> #{ Example.fibonacci_hs x }\n"
end

Example.example_exit

Makefile

GHC=ghc-6.12.1

libffi-example.so: Example.o wrapper.o Example_stub.o
    $(GHC) -o $@ -shared -dynamic -fPIC $^ -lHSrts-ghc6.12.1

Example_stub.c Example_stub.h Example.o: Example.hs
    $(GHC) -c -dynamic -fPIC Example.hs

Example_stub.o: Example_stub.c
    $(GHC) -c -dynamic -fPIC Example_stub.c

wrapper.o: wrapper.c Example_stub.h
    $(GHC) -c -dynamic -fPIC wrapper.c

clean:
    rm -f *.hi *.o *_stub.[ch] *.so

Commands to run

make
ruby script.rb