2011-11-14 12 views
4

ハスケルのバイナリデータをシリアライズ/デシリアライズするボイラープレートコードを削除し、エンディアンを考慮に入れて最適な方法はありますか?ハスケルでバイナリリトルエンディアンデータをデコード/エンコードするより良い方法は何ですか?

data Foobar = Foobar { foo :: Word16, bar :: Word32 } 

そしてData.Binary.Binary型クラスのインスタンスを派生:ビッグエンディアンとして

instance Binary Foobar where 
    get = do 
    foo <- get 
    bar <- get 
    return $ Foobar foo bar 

decode stream :: Foobar扱いのデータを、すなわち、この構造体を与えられました。

明白な方法はgetWord16le/getWord32le機能を使用することですが、それは(自動的にうまくderiveと相まってテンプレートハスケルによって行うことができる)、マニュアル作業の多くを必要とします。

おそらく、パラメータ化された型がソリューションですか?

+0

バイナリの事前宣言されたインスタンスは常にビッグエンディアンではありませんか?ビッグエンディアンとリトルエンディアンの両方で作業することは、難解なエラーのレシピのように見えます。既存のリトルエンディアンのバイナリ形式でデータを記述して解析する場合は、バイナリのインスタンスを作成しないで、パーサーとシリアライザを型クラスなしで直接記述することをお勧めします。 –

答えて

8

リトルエンディアンの新しいタイプの単語を定義するのはどうですか?

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

次に定義

data Foobar = Foobar { foo :: LWord16, bar :: LWord32 } 

用のバイナリを導出することは正しいことを行う必要があります。

+1

それは働いた - ありがとう! また、この場合、 'GeneralizedNewtypeDeriving'が非常に役に立ちます。 – NikitaBaksalyar

+1

後世のため:最近、 'instance Binary LWord16、get = coerce getWord16le;と書かれています。 put = coerce putWord16le'を実行して、 'fmap'を呼び出す(おそらく非常に小さい)オーバーヘッドを避けます。 –

2

次のような異なる単語の種類、用型クラスを定義することができます。

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

instance BinaryEndian Word16 where 
    getEndian = getWord16le 
    putEndian = putWord16le 

などTHコードになるだろう

書き込みが簡単、おそらく少し。

関連する問題