Reputation: 2514
What is a best approach to get rid of a boilerplate code that serializes/deserializes binary data in Haskell, taking endianness into account? I.e., given this struct:
data Foobar = Foobar { foo :: Word16, bar :: Word32 }
And derived Data.Binary.Binary
type class instance:
instance Binary Foobar where
get = do
foo <- get
bar <- get
return $ Foobar foo bar
decode stream :: Foobar
treats the data as big endian.
Obvious way is to use getWord16le
/getWord32le
functions, but it involves lots of manual work (which could be automatically and nicely done by Template Haskell coupled with derive).
Perhaps, parametrized types are the solution?
Upvotes: 4
Views: 906
Reputation: 153342
How about defining little-endian newtypes for words?
newtype LWord16 = LWord16 { unLWord16 :: Word16 }
newtype LWord32 = LWord32 { unLWord32 :: Word32 }
instance Binary LWord16 where get = LWord16 <$> getWord16le
instance Binary LWord32 where get = LWord32 <$> getWord32le
Then deriving Binary for the definition
data Foobar = Foobar { foo :: LWord16, bar :: LWord32 }
should do the right thing.
Upvotes: 8
Reputation: 5279
You can define a typeclass for different Word types, such as:
class BinaryEndian a where
getEndian :: Get a
putEndian :: a -> Put
instance BinaryEndian Word16 where
getEndian = getWord16le
putEndian = putWord16le
etc.
That would make TH code perhaps a little easier to write.
Upvotes: 2