
Hi, 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, nt