
On Wed, 2011-04-27 at 20:16 +0200, John Obbele wrote:
Hi Haskellers,
I'm currently serializing / unserializing a bunch of bytestrings which are somehow related to each others and I'm wondering if there was a way in Haskell to ease my pain.
The first thing I'm looking for, is to be able to automatically derive "Serializable" objects, for example:
--------------------------------------------------------------- import Data.Serialize -- using cereal as an example
data MyFlag = One | Two | Three
instance Serialize [MyFlag] where put = putWord16le . marshalFlags get = unmarshal `fmap` getWord16le
data ObjectA = ObjectA { attribute0 :: Word8 , attribute1 :: Word16le , attribute2 :: [MyFlag] } deriving (Serialize) -- magic goes here! ---------------------------------------------------------------
Unfortunately ghci complains that 'Serialize' is not a derivable class. Yet, deriving the Serialize instance for ObjectA should be simple, since all the three attributes are already serializable themselves...
Second issue, I would like to find a way to dispatch parsers. I'm not very good at expressing my problem in english, so I will use another code example:
--------------------------------------------------------------- -- let's say we have two objects with almost the same structure: data ObjectA = ObjectA { objLength :: Int , objType :: TypeId , attribute2a :: [MyFlag] }
data ObjectB = ObjectB { objLength :: Int , objType :: TypeId , attribute2b :: Word32le } ---------------------------------------------------------------
When we begin to deserialize theses objects, we don't know their final type, we just know how to read their length and their typeId.
Only then can we determine if what we are parsing is an ObjectA or an ObjectB.
Once we now the object type, we can resume the parsing and return either an ObjectA or ObjectB.
Oki, so I may have read too much of Peter Seibel's chapter on binary-data parsing in Common Lisp or spent too much time working on object-oriented code, but currently, I have no idea on how to write this 'simply' in Haskell :(
I believe following should work class Serializer ObjectA where get = check =<< (ObjectA <$> get <*> get <*> get) where check obj@(ObjectA len id attr) | len < 10 && id == 0 = return obj | otherwise = empty class Serializer ObjectB where get = check =<< (ObjectB <$> get <*> get <*> get) where check obj@(ObjectB len id attr) | len > 10 && id == 1 = return obj | otherwise = empty parseEitherAB :: Get (Either ObjectA ObjectB) parseEitherAB = (Left <$> get) <|> (Right <$> get) Regards
any help would be welcome /john