
Er, how exactly does a state transformer allow my implementation of put :: BinHandle -> a -> IO (BinPtr a) to get at the extra state?
Sorry, wasn't thinking clearly. I guess what I had in the back of my mind was something like this: What if all the functions had, instead of type signature '... -> IO a', had signature 'MonadIO m => ... -> m a'? Presumably this could be done, essentially lifting all the IO operations into a monad transformer inside the Binary class. Then the Binary implementation is happy because it can use IO as it sees fit, and you're happy because you can piggy-back whatever you want on top of IO. This all goes back to SimonM's original questions as to whether there would be much to be gained from allowing BinMem operations in ST. If the answer is "not much", then the MonadIO solution seems reasonable.
That's not quite what I want, what I want is a way of reading a type with an existing binary representation, throwing an exception if you try to read too many characters. Of course it's possible with Malcolm's framework to define a set of parallel types to the standard Haskell ones (UntrustedInt, UntrustedString, and so on) and define new instances of Binary for the lot, but this would be painful in general. And you'd have to do it all over again should you want to put something else inbetween the individual read/write operations (logging, online compression, and so on) and the actual output.
The reason I used String is because it seems somewhat strange to define a maximum number of "characters" for an arbitrary type. It seems that the maximal amount to read should depend on the type you are reading; otherwise you might end up reading only enough to represent half of your data structure. I think perhaps the best you can do in this situation is just to read an array of word8s of some length and then let your own function do the checking. I understand the intent of only reading a certain amount from an untrusted source, but I'm still unclear as to how it actually works. - Hal