我正在尝试编写一个从文件中读取原始字节的函数,将其“转换”为“普通”类型,然后对其进行排序。
为了做到这一点,我需要告诉排序它应该如何解释二进制数据——即,二进制数据的类型是什么。
为了使其成为“二进制”数据,在“我可以将这些数据视为原始位,因为我从磁盘读取和写入它”的意义上,数据的类型必须是二进制和位。而且,要对其进行排序,它必须是 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 中复制出来,并在每次想要重新配置排序时创建一个新记录?