[Haskell-cafe] Data.Binary questions

Derek Elkins derek.a.elkins at gmail.com
Mon Jan 21 14:23:03 EST 2008


On Mon, 2008-01-21 at 16:18 +0000, Lauri Pesonen wrote:
> Hi Derek,
> 
> Thanks for the reply.
> 
> On 20/01/2008, Derek Elkins <derek.a.elkins at gmail.com> wrote:
> 
> > You may want to consider using the other side of Data.Binary rather than
> > the Binary class.  The -class- Binary is intended for de/serialization
> > when you don't care about the format.  From the documentation:
> >
> > "For parsing and generating simple external binary formats (e.g. C
> > structures), Binary may be used, but in general is not suitable for
> > complex protocols. Instead use the Put and Get primitives directly."
> 
> Yes, you are right. I read that bit of the documentation, but didn't
> understand how to use the Get and Put primitives. So I started by
> using the Binary class and after getting quick results carried on with
> it. I'll rewrite what I have with Get and Put once I figure out how
> they actually work.
> 
> > Nevertheless, one way to solve your problem is with a phantom type.
> > Change MyList to,
> > newtype MyList t e = MkList [e] deriving Show
> >
> > getLengthType :: MyList t e -> t
> > getLengthType = undefined
> >
> ...
> >
> > The asTypeOfs are just to propagate the type information around.  GHC's
> > extension for scoped type variables would make this code simpler and
> > more direct.  At any rate, now the code will use the Binary instance for
> > whatever type t is to serialize the length.
> 
> Ah, very clever. Is this a common idiom in Haskell?

Phantom types are a very common technique.  They allow you to use the
static type system to enforce guarantees (and, in this case, generate
code).  Essentially they let you add types to an untyped representation
giving you the benefits of both. Usually you can avoid doing the
asTypeOf chicanery I did.

> > If you mean that you there references to the constant table in e.g. the
> > fields table then the problem here is that you need to the class methods
> > to use that monad transformer (in this case, ReaderT is all you should
> > need and not even that), but you can't change their type.  These are the
> > kind of issues that make the Binary class unsuitable for this type of
> > work.  If that is the case, the only way to use this is to explicitly
> > write out the deserialization code rather than relying on get, i.e.
> > you'll have to write a function 'getTable constantTable' that will
> > deserialize the table.
> 
> As an example, a method is serialised in the class file as the
> following structure:
> 
>   method_info {
>     	u2 access_flags;
>     	u2 name_index;
>     	u2 descriptor_index;
>     	u2 attributes_count;
>     	attribute_info attributes[attributes_count];
>     }
> 
> Both the name_index and the descriptor_index are indices that point
> into the constants pool. In Haskell I would represent this as the type
> 
> data Method = Method Access String String [Attribute]
> 
> So I want to replace the indices with the actual strings that they
> point to. I guess in the final deserialised version of the class file
> the constant pool would not exist at all and it would be recreated
> when the class file is serialised again.
> 
> So, AFAICT, I should be able to first deserialise the constants table
> as part of deserialising the whole class file and then pass the
> constant pool into the functions that deserialise fields, methods etc.
> so that they are able to look up the constants from the pool.
> 
> I have to stare at the Get and Put primitives as well as ReaderT to
> figure out how all this will work together. Let's call it a learning
> experience.

As I hinted, ReaderT isn't really necessary either in this case.  All it
amounts to is passing an extra parameter.  In this case it is probably
clearer and simpler to explicitly pass the extra parameter, though you
can decide that for yourself.

Anyway, this documentation page may be more useful:
http://hackage.haskell.org/packages/archive/binary/0.4.1/doc/html/index.html

Basically your code will look similar to what it does now except instead
of using get you'll use getWord32le or whatever and your own functions
that will deserialize more involved structures, e.g. a getTable
function.



More information about the Haskell-Cafe mailing list