在Haskell中解码/编码二进制小端数据的更好方法是什么?

在Haskell中解码/编码二进制小端数据的更好方法是什么?,haskell,Haskell,考虑到endianness,消除Haskell中序列化/反序列化二进制数据的样板代码的最佳方法是什么?即,给定此结构: data Foobar = Foobar { foo :: Word16, bar :: Word32 } 和派生的Data.Binary.Binary类型类实例: instance Binary Foobar where get = do foo <- get bar <- get return $ Foobar foo bar 实

考虑到endianness,消除Haskell中序列化/反序列化二进制数据的样板代码的最佳方法是什么?即,给定此结构:

data Foobar = Foobar { foo :: Word16, bar :: Word32 }
和派生的
Data.Binary.Binary
类型类实例:

instance Binary Foobar where
  get = do
    foo <- get
    bar <- get
    return $ Foobar foo bar
实例二进制Foobar,其中
得到=做

foo您可以为不同的单词类型定义typeclass,例如:

class BinaryEndian a where
   getEndian :: Get a
   putEndian :: a -> Put

instance BinaryEndian Word16 where
   getEndian = getWord16le
   putEndian = putWord16le
等等


这可能会使代码编写起来更容易一些。

如何定义单词的小尾端新类型

newtype LWord16 = LWord16 { unLWord16 :: Word16 }
newtype LWord32 = LWord32 { unLWord32 :: Word32 }
instance Binary LWord16 where get = LWord16 <$> getWord16le
instance Binary LWord32 where get = LWord32 <$> getWord32le

应该做正确的事情。

二进制文件的预声明实例不总是big-endian吗?同时使用big和little endian看起来像是一种难以理解的错误。如果您想以预先存在的little endian二进制格式编写和解析数据,我建议您避免创建二进制实例,直接编写没有类型类的解析器和序列化程序。这很有效-谢谢!另外,
generalizednewtypedering
在这种情况下非常有用;put=强制putWord16le
以避免调用
fmap
的开销(可能非常小)。
data Foobar = Foobar { foo :: LWord16, bar :: LWord32 }