0MQ and Haskell

Ever since I heard the FLOSS weekly episode on 0MQ I’ve been looking for a reason to take a look at it. Well, to hell with reason, I’ll have a first look without any specific goal in mind.

I found a simple introduction to it in Nicholas Piël’s post ZeroMQ an introduction. The only issue was that it was based on Python, and Python2 at that. So here are my attempts at translating two of the clients to Haskell (using zeromq-haskell).

req-rep

Here’s the client in Python3 first:

1
2
3
4
5
6
7
8
9
10
11
import zmq
 
ctx = zmq.Context()
socket = ctx.socket(zmq.REQ)
socket.connect('tcp://127.0.0.1:5000')
 
for i in range(10):
    msg = "msg %s" % i
    socket.send_unicode(msg)
    print('Sending', msg)
    msg_in = socket.recv()

And here in Haskell:

1
2
3
4
5
6
7
8
9
10
import System.ZMQ
import Data.ByteString.Char8 as CBS
 
main = withContext 1 $ \ ctx -> withSocket ctx Req $ \ soc -> do
    connect soc "tcp://127.0.0.1:5000"
    let msgs = [pack ("msg " ++ show i) | i <- [0..9]]
    flip mapM_ msgs $ \ msg -> do
        send soc msg []
        CBS.putStrLn msg
        receive soc []

pub-sub

In Python3:

1
2
3
4
5
6
7
8
9
10
import zmq
 
ctx = zmq.Context()
socket = ctx.socket(zmq.SUB)
socket.connect('tcp://127.0.0.1:5000')
socket.setsockopt(zmq.SUBSCRIBE, b'sweden')
socket.setsockopt(zmq.SUBSCRIBE, b'denmark')
 
while True:
    print(socket.recv())

Haskell:

1
2
3
4
5
6
7
8
9
import System.ZMQ
import Control.Monad
import Data.ByteString.Char8 as CBS
 
main = withContext 1 $ \ ctx -> withSocket ctx Sub $ \ soc -> do
    connect soc "tcp://127.0.0.1:5000"
    subscribe soc "sweden"
    subscribe soc "denmark"
    forever $ receive soc [] >>= CBS.putStrLn

Two comments on the Haskell code here:

  • I’m not sure why, but the Haskell client dies after receiving just a few messages (they are properly filtered though).
  • The API for subscribe is a bit strange, it would make more sense if it took a ByteString rather than a String.
Share

6 Comments

  1. I’m not sure why, but the Haskell client dies after receiving just a few messages (they are properly filtered though).

    Someone should write a blog post where they successfully debug a problem like this. That would be a pretty interesting display of real world Haskell and its development tools.

  2. Xavier Lange and I have been working on a pure Haskell implementation of 0MQ too. I’ve been using the binding pretty heavily, but there are some things you can’t do directly with it. Still, it’s exciting technology, I’ve put a large part of ninjablocks.com’s back end onto it (albeit using ruby) and I’m looking forward to shifting more of it to Haskell.

    http://github.com/ninjablocks/zmqhs (at least until Xavier pulls my changes in)

  3. @Mark, Cool, do you already have some numbers comparing your pure Haskell implementation against the FFI implementation in zeromq?

  4. @Magnus not yet, it’s still at a very early stage. We can successfully receive and send messages, but we haven’t got proper support for the different socket types. I’m a bit torn here, actually – the C implementation uses a state machine to model the allowable patterns (ie, a REQ socket has to send then receive in strict alternation, and vice-versa for a REP socket) – it feels like something we ought to be able to model in the type system in Haskell.

    Interestingly, I’ve found it changes the way I write C much more than the way I write Haskell. The appeal for Haskell is in being able to interoperate with other runtimes, i think: if you just wanted intra-process coordination, you already have cheap threads and MVar/TVar/STM etc.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>