[Haskell-cafe] How to implement this? A case for scoped record labels?

ntupel at googlemail.com ntupel at googlemail.com
Mon May 25 08:20:20 EDT 2009


I would like to get some advice on how to best implement a protocol.
The protocol in question is "Bayeux":
http://svn.cometd.org/trunk/bayeux/bayeux.html. The details don't
matter here - it defines a couple of requests and responses in JSON
format, basically JSON objects with different properties, some of
which are shared by all (e.g. "channel") and some which are specific
for certain kinds of requests/responses (e.g. "subscription"). To give
an example, a connect request would look like this:

     "channel": "/meta/connect",
     "clientId": "Un1q31d3nt1f13r",
     "connectionType": "long-polling"

Now I leave the actual JSON parsing to the excellent Text.JSON
library. My problem is how to get the types right.

At first I started with a big discriminated union, e.g.

data BayeuxMessage = HandshakeRequest { channel :: String , ... }
     | HandshakeResponse { channel :: String, successful :: Bool, ... }
     | ...

This way I could create BayeuxMessage values by copying the Text.JSON
parsed values over. However what I don't like is that many selector
functions, e.g. successful, are only partial and using them with a
BayeuxMessage value constructed with HandshakeRequest for example will
result in a runtime error. So I think it would be better to have
individual types for the protocol requests/responses, e.g.

data HandshakeRequest = HandshakeRequest { channel :: String , ... }
data HandshakeResponse = HandshakeResponse { channel :: String,
successful :: Bool, ... }

data BayeuxMessage = HSReq HandshakeRequest
    | HSRes HandshakeResponse

This however does not work because record selectors have module scope,
so the compiler will complain that channel et. al. are defined
multiple times. As a workaround I could put each type into its own
module, but at least GHC requires a file per module (which is *very*
inconvenient IMO). If we would have scoped labels (e.g. like proposed
here: http://legacy.cs.uu.nl/daan/pubs.html#scopedlabels) it seems
like it would have been straightforward.

So certainly I am missing something and there is a better way to
design this. Hence this e-mail. I welcome any advice how this would
best be done in Haskell with GHC.

Many thanks,

More information about the Haskell-Cafe mailing list