ファイルから生のバイトを読み取り、それを「プレーン」タイプに「キャスト」してからソートする関数を作成しようとしています。
これを行うには、バイナリ データをどのように解釈するか、つまりバイナリ データの型をソートに伝える必要があります。
「バイナリ」データであるためには、「このデータをディスクから読み書きするため、生のビットとして扱うことができる」という意味で、データのタイプはバイナリおよびビットでなければなりません。そして、並べ替えるには、Ord のメンバーである必要があります。
これらの方法で制約された型は、並べ替え可能である必要があります。
ちょっとしたハックとして、型をソート関数に渡すために、代わりに型の住民を渡しています。(型自体を渡して結果を達成する方法があれば、知りたいです。)
{-# LANGUAGE RankNTypes #-}
import Data.Binary.Get
import Data.Binary.Put
type Sortable = forall a. (Bits a, Binary a, Ord a) => a
data SortOpts = SortOpts { maxFiles :: Int
, maxMemory :: Integer
, maxThreads :: Int
, binType :: Sortable
}
defaultOpts = SortOpts { maxFiles = 128
, maxMemory = 1000 * 1000 * 1000 * 1000
, maxThreads = 4
, binType = 0 :: Word32
};
putBinaryValues :: Binary a => Handle -> [a] -> IO ()
putBinaryValues out vals = do
let bytes = runPut . mapM_ put $ vals
BL.hPut out bytes
binaryValues :: (Binary a, Bits a) => a -> Handle -> IO [a]
binaryValues t inf = do
size <- hFileSize inf
let cast = runGet (genericReplicateM (size `div` byteWidth) get)
cast . BL.fromChunks . (:[]) <$> BS.hGetContents inf
where genericReplicateM n = sequence . (DL.genericReplicate n)
byteWidth = fromIntegral $ (bitSize t) `div` 8
しかし、これはコンパイルされません。Haskell は、レコードのすべての値が具象型であると主張しているようです。少なくとも、それは私がエラーメッセージから集めているものです:
Could not deduce (a ~ Word32)
from the context (Bits a, Ord a, Binary a)
bound by a type expected by the context:
(Bits a, Ord a, Binary a) => a
at ...
`a' is a rigid type variable bound by
a type expected by the context: (Bits a, Ord a, Binary a) => a
では、どうすればこの一般化を達成できるでしょうか?
編集:
ソートを「構成」するためにレコード更新構文を使用したかったのです。例えば:
configure = defaultOpts -- and exporting that
以降
let myOpts = configure{ binType = 42 :: Word16 }
しかし、これは機能しません。NYI だけでない限り、その理由がよくわかりません。
Record update for insufficiently polymorphic field: binType :: a
In the expression: configure {binType = words !! 0}
In an equation for `o': o = configure {binType = words !! 0}
In the expression:
do { inTestHandle <- inTest;
words <- testRandomWords;
putBinaryValues inTestHandle $ take 100 words;
seekBeg inTestHandle;
.... }
では、私のクライアント コードは、defaultOpts から値を少しずつコピーし、並べ替えを再構成するたびに新しいレコードを作成するだけでよいのでしょうか?