私は大規模な(10-1000 GB)メモリマップバイナリファイルと相互作用するアプリケーションを作成しています。私はこのデータを読み書きする仕組みを考え出しましたが、これは効果的ですが、醜く冗長です(imo)。Haskellで大規模な構造化バイナリデータを保存する
Q:私が行ったことを達成するためのよりエレガントな方法はありますか?
私はHaskellのデータ型(DataOp
がIO
周りReaderT
である)に構造を読み出す一つの方法では、構造化データの型クラスを有しています。
class DBStruct a where
structRead :: Addr a -> DataOp a
これを読みやすくするために、私は、構造体のメンバがどこに行くかを定義し、別の型クラスがあります。
class DBStruct st => StructMem structTy valTy name | structTy name -> valTy where
offset :: structTy -> valTy -> name -> Int64
を私は構造要素を書き込み/読み出し用のオフセット方法を使用するいくつかのヘルパー関数を持っています、格納された参照から構造を読み込み、構造読み取りを遅らせる(ファイル全体の読み込みを遅らせる)ためのものです。
この問題は、使用に多くの繰り返しが含まれているということです。次に、構造体を
instance StructMem RowBlock (Maybe (Addr RowBlock)) Next where offset _ _ _ = 0
instance StructMem RowBlock (Maybe (Addr RowBlock)) Prev where offset _ _ _ = 8
instance StructMem RowBlock Int64 Count where offset _ _ _ = 16
instance StructMem RowBlock RowTy Row where offset _ _ (Row n) = 24 + n * 8
:そして
data RowBlock = RowBlock {rbNext :: Maybe RowBlock
,rbPrev :: Maybe RowBlock
,rbRows :: [RowTy]
}
name
タイプ:そして
data Next = Next
data Prev = Prev
data Count = Count
newtype Row = Row Int64
各構造部材のためのインスタンスを一つの構造のために、私は最初Haskellのタイプを定義する必要があります読み取り方法:
instance DBStruct RowBlock where
structRead a = do
n <- elemMaybePtr a Next
p <- elemMaybePtr a Prev
c <- elemRead a Count
rs <- mapM (elemRead a . Row) [0 .. c-1]
return $ RowBlock n p rs
私が本当に達成したのは、C構造体をはるかに冗長な(そして遅い)方法で再実装することだけです。タイプの安全性を維持しながら、これがより簡潔であれば私はもっと幸せです。確かにこれは一般的に遭遇する問題です。
- ディッチのメモリマップドファイルやディスクへの通常の方法を
ByteStrings
を書いて、Data.Binary
を使用します。私は考えることができるいくつかの可能な選択肢があります。
- モナドのレンズとの不思議な何かをする
- Overload Functional References
- の機能を一般的な読み取りを作成し、書き込みに使用
deriving Generic
。
EDIT:SSCCE as requested
コンパイルすることができる、簡単で自立的な例を用意してください。 –
@PetrPudlákもし人々が答えを出すのを助けると思うなら、今日後でそれをすることができます。しかし、これは、なぜ私のコードの問題ではないのかという建築上の疑問であることを意味していました。投稿したコードは、私の現在のアーキテクチャを他のものよりも具体的に説明するためのものです。 – Dan
はい、[SSCCE](http://www.sscce.org/)は、現在のデザインをよりよく理解するのに役立ちます。 –