[Haskell-cafe] AMQP framing layer: design help requested.

Paul Johnson paul at cogito.org.uk
Fri Mar 21 14:02:18 EDT 2008

I'm trying to implement the AMQP framing layer.  This is the bottom 
layer of the protocol that packs and unpacks data in lazy ByteStrings.  
I'm using the Binary package with its "Get" and "Put" monads to do the 
unpacking, and that works well.  But I've run into a problem and I can't 
find an elegant solution.  I'm wondering if someone can help.  The 
following contains a simplified version of my current design.

I've mapped the AMQP basic types to Haskell types.  Sometimes this is a 
basic mapping, sometimes to something more complex.  Strings have 
several AMQP representations, so I've created corresponding newtype 
declarations and instances.

Some AMQP types can contain tagged types.   For instance a "map" 
contains (key, tag, value) triples, where the tag is a single byte 
indicating the type of the value.

I've defined the following type:

   data AmqpVariant = AmqpVarWord8 Word8 | AmqpVarWord16 Word16 | 
AmqpVarStr8 Str8
          -- And so on for about 20 more types

   instance Binary AmqpVariant where
      put (AmqpVarWord8 v)= putWord8 0x01 >> putWord8 v
      put (AmqpVarWord16 v) = putWord8 0x02 >> putWord16be v
      put (AmqpVarStr8 v) = putWord8 0x03 >> put v
        -- And so on for about 20 more types
      get = do
         getter <- fmap (amqpGetTable !)  getWord8

   amqpGetTable :: Array Word8 (Get AmqpVariant)
   amqpGetTable = array (0,255) [
      (0x01, fmap AmqpVarWord8 getWord8),
      (0x02, fmap AmqpVarWord16 getWord16be),
      (0x03, fmap AmqpVarStr8 get),
         -- And so on for about 20 more types

This is a Brute Force and Ignorance solution, but it will probably 
work.  But now I've come up against another type, which AMQP calls an 
"array".  This has a single type tag at the start, followed by N items 
of that type.  I'm wondering how to do this.

One option would be to declare

   data AmqpArray = AmqpArrWord8 [Word8] | AmqpArrWord16 [Word16] -- and 
so on

This effectively duplicates the AmqpVariant solution.  It would work, 
but it feels horrible.  I get the feeling that there ought to be a 
better way, possibly using classes or existential types.  Any suggestions?



More information about the Haskell-Cafe mailing list