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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With