いくつかのデータ型があらかじめ定義されており、それらはTLV(type length value)で統一的に符号化されるとします。
これに対する符号器/復号器の基本ライブラリを作りますが、データ型は将来追加されるかもしれないので、サードパーティライブラリで拡張可能としたいです。
まず、符号化のために以下のようなクラスを定義します。
既存のデータを表す型を A と B とすると、
これらの型を同じように扱えるように、
符号器で encode を使うのは、
問題は復号器です。TLVのTとLの部分は
ぱっと思いつくのは、
基本的に reflaction に関係する問題だと思います。サードバーティが
これに対する符号器/復号器の基本ライブラリを作りますが、データ型は将来追加されるかもしれないので、サードパーティライブラリで拡張可能としたいです。
まず、符号化のために以下のようなクラスを定義します。
class Typeable a => T a where typeT :: Int encode :: T -> ByteString decode :: ByteString -> T fromTLV :: TLV -> Maybe a -- TLVは後述 fromTLV (TLV x) = cast x toTLS :: a -> TLV toTLS = TLV
既存のデータを表す型を A と B とすると、
data A = A ... data B = B ... instance A where typeT = 0 encode = ... decode = ... instance B where typeT = 1 encode = ... decode = ...
これらの型を同じように扱えるように、
ExistentialQuantification
を用いて、以下の型を定義します。data TLV = forall a. T a => TLV a
符号器で encode を使うのは、
a
が与えられるので簡単です。encodeTLV :: TLV -> ByteString encodeTLV (TLV x) = encode x
問題は復号器です。TLVのTとLの部分は
ByteString
に符号化された整数なので、それをパースして V の部分の ByteString
を切り出した後に、適切な decode
を呼ぶだしたいのですが、どうすれば呼べるでしょうか?ぱっと思いつくのは、
Int -> ByteString
の辞書を用意して、それを引くことです。拡張可能にするのは、この辞書を公開し、利用時に要素を追加可能にする必要がありそうです。基本的に reflaction に関係する問題だと思います。サードバーティが
data C
を定義したら、自動的にその decode
も呼ばれるような魔法はあるのでしょうか?