3
votes

I am trying to learn Haskell and struggling with binary IO. This code is adapted from the code given in this answer to one of my earlier questions.

I am trying to read a lot of Word32 values and a few Word8 values (metadata) from a given file. Currently, I have written a program that just reads Word32 values from a file into an unboxed vector.

The trouble with this code is it uses list (via replicateM) while reading multiple Word32 values from a file. I want to get rid of the intermediate list (for efficiency reasons) and want to read the data directly in the vector from the file using ByteString.

Here is my complete working code.

import Data.Word
import qualified Data.ByteString.Lazy as BIN
import Data.Binary.Get
import Data.Binary.Put
import qualified Data.Vector.Unboxed as V
import Control.Monad
import System.IO

main = do
  h_in  <- openFile "dat.bin" ReadMode
  v <- readInVector 10 h_in 
  putStrLn (show v)
  hClose h_in

readInVector n h_in = do
 bin1 <- BIN.hGet h_in (n*100)
 let ints1 = runGet (replicateM n getWord32le) bin1
 let v = V.fromList (ints1) :: V.Vector Word32
 return v

How to do this? I wish a complete working code as answer, not just pointers to documentation on Haskell site which has a lot of text with almost no working examples.

1
I wonder is that intermediate list would be optimized out due to fusion.Yuuri

1 Answers

7
votes

The vector-package has its own replicateM function for vectors which you can use to directly initialize a vector without building an intermediate list.

readInVector n h_in = do
  bin1 <- BIN.hGet h_in (n*100)
  return $ runGet (V.replicateM n getWord32le) bin1