我正在尝试将二进制文件解析为haskell向量。我可以将我的文件加载到常规列表中,但由于每个文件有超过10000000个元素,因此我的表现非常糟糕。
要解析二进制文件,我使用Data.Binary.Get
和Data.Binary.IEEE754
,因为我打算读取浮点值。我正在尝试将我的矢量构建为Mutable,然后将其冻结。
我最终遇到问题,因为Get
不是Control.Monad.Primitive.PrimMonad
的实例,对我来说这看起来很模糊。
import qualified Data.ByteString.Lazy as B
import qualified Data.Vector.Unboxed.Mutable as UM
import qualified Data.Vector.Unboxed as U
import Data.Binary.Get
import Data.Binary.IEEE754
type MyVectorOfFloats = U.Vector Float
main = do
-- Lazyly read the content of the file as a ByteString
file_content <- B.readFile "vec.bin"
-- Parse the bytestring and get the vector
vec <- runGet (readWithGet 10) file_content :: MyVectorOfFloats
-- Do something usefull with it...
return ()
readWithGet :: Int
-> Get MyVectorOfFloats -- ^ Operates in the Get monad
readWithGet n = do
-- Initialize a mutable vector of the desired size
vec <- UM.new n
-- Initialize the vector with values obtained from the Get monad
fill vec 0
-- Finally return freezed version of the vector
U.unsafeFreeze vec
where
fill v i
| i < n = do
-- Hopefully read one fload32 from the Get monad
f <- getFloat32le
-- place the value inside the vector
-- In the real situation, I would do more complex decoding with
-- my float value f
UM.unsafeWrite v i f
-- and go to the next value to read
fill v (i + 1)
| otherwise = return ()
上面的例子非常简单,在我的情况下我有run-length喜欢解码,但问题保持不变。
首先,我选择的库是否足以供我使用?我目前并不真正需要内存中的所有向量。我可以操作块。来自pipe或Conduit的东西看起来很有趣。
我是否必须让Get
Control.Monad.Primitive.PrimMonad
的实例做我想做的事情?
我想我可以尝试做一些展开模式来构建没有可变状态的向量。
答案 0 :(得分:1)
如果您不需要同时获取所有数据,则应该使用流式库。 (如果事情很简单,你可能会使用懒惰的I / O.)
您的错误来自于您已声明'do'块在Get monad中运行,但UM.new只能在ST或IO monad中运行。你需要将readWithGet更改为IO或ST monad,尽管它仍然可以在“引擎盖下”使用Get monad(并在内部调用runGet)。
以下是我在Get和Parser之间进行转换的方法(来自pipe-parse):
type GetParser m a = Parser ByteString (EitherT GetFail m) a
data GetFail = GetFail !ByteOffset String
get2parser :: Get a -> GetParser m a
get2parser = decoder2parser . runGetIncremental
decoder2parser :: Decoder a -> GetParser m a
decoder2parser (Fail r off err) = unDraw r >> lift (left $ GetFail off err)
decoder2parser (Partial cont) = draw >>= decoder2parser . cont
decoder2parser (Done r _ a) = unDraw r >> return a