Applications and libraries/Interfacing other languages/Erlang
The Haskell/Erlang-FFI enables full bi-directional communication between programs written in Haskell and Erlang. Message sends from Haskell to Erlang just look like function calls (of course), and messages from Erlang to Haskell are delivered to MVars.
2 Theory of Operation
Because everything interesting that happens in Erlang happens as a result of sending a message, all that is required to fully interoperate with Erlang is to be able to send and receive messages using its native wire protocol. There are similar packages that allow Erlang to interoperate with programs written in C, Java, Clojure, Scheme, Emacs Lisp, Python, and Ruby. This Haskell library is distantly derived from the Emacs Lisp package Distel.Erlang types are represented in Haskell with the
ghci> toErlang [("a", 1), ("b", 2)] ErlList [ErlTuple [ErlString "a",ErlBigInt 1],ErlTuple [ErlString "b",ErlBigInt 2]] ghci> fromErlang $ ErlList [ErlTuple [ErlString "a",ErlBigInt 1],ErlTuple [ErlString "b",ErlBigInt 2]] :: [(String, Int)] [("a",1),("b",2)]
3 Getting Started
Before you can do anything with the Erlang FFI, you minimally need to start up the Erlang Port Mapper Daemon (epmd). The simplest way to do that is to start an Erlang node on the local machine.Having started Erlang, we can now create a Haskell node. The
self <- createSelf "haskell@localhost"
mbox <- createMBox self
You are now ready to talk to Erlang.
4 Low-Level Communication
Erlang's fundamental abstraction is an asynchronous message send. In Haskell that's:
mboxSend mbox node pid msg
mboxSend mbox "erlang" (Right "echo") (mboxSelf mbox, "Hello, Erlang!")
Receive messages addressed to your "process" with:
msg <- mboxRecv mbox
You will generally initiate communication to a registered name, at which time you may receive a Pid for later use.
5 High-Level Communication
In a real Erlang program, low-level message sends are not used for the bulk of the work. Most of the interesting things in Erlang are part of the OTP (Open Telecom Platform) libraries, and these implement higher-level protocols on top of message sends.
The most important of these protocols is
gen_server. When talking to a process that implements the
gen_server protocol, you can either "call" or "cast" to it (in addition to still being able to do low-level message sends). A call is a two-way faux-synchronous request/response:
reply <- genCall mbox node pid msg
A cast is a one-way notification:
genCast mbox node pid msg
One instance of
gen_server in particular is very useful: the RPC server "rex". Send rex a message containing a module name, function name, and a list of arguments, and it will (synchronously or asynchronously) call the named function in the named module, passing it the arguments supplied, and optionally returning the results to you. The RPC server gives you access to nearly all of Erlang:
reply <- rpcCall mbox node module function arguments
rpcCast mbox node module function arguments
The library also provides a set of wrappers for making calls to Mnesia.
6 Not Implemented
The Erlang FFI is a work in progress, and it has some shortcomings. As of this writing, it does not yet register itself with epmd. This means that, even though Erlang can call into Haskell, Haskell must initiate first contact with the Erlang node. (Otherwise Erlang simply doesn't know where the Haskell node is on the network).
A larger issue is that the FFI does not yet implement process linking. Two processes are "linked" in Erlang if one is notified when the other terminates, and linking is the primary mechanism for handling and/or propagating errors in an Erlang system. This is in-progress and should be completed soon. Until it is done, this library is best suited for situations where Haskell is consuming Erlang services. Erlang can't yet reliably consume Haskell services because there is no error notification.
7 Future Plans
To complete the items listed in the previous section. :)