views:

305

answers:

2

Attempting to use Data.Binary.Get and ByteString and not understanding what's happening. My code is below:

getSegmentParams :: Get (Int, L.ByteString)
getSegmentParams = do 
    seglen <- liftM fromIntegral getWord16be
    params <- getByteString (seglen - 2)
    return (seglen, params)

I get the following error against the third item of the return tuple, ie payload:

Couldn't match expected type `L.ByteString'
       against inferred type `bytestring-0.9.1.4:Data.ByteString.Internal.ByteString'

Someone please explain to me the interaction between Data.Binary.Get and ByteStrings and how I can do what I'm intending. Thanks.

+1  A: 

There are two ByteString data types: one is in Data.ByteString.Lazy and one is in Data.ByteString.

Given the L qualifying your ByteString, I presume you want the lazy variety, but getByteString is giving you a strict ByteString.

Lazy ByteStrings are internally represented by a list of strict ByteStrings.

Fortunately Data.ByteString.Lazy gives you a mechanism for turning a list of strict ByteStrings into a lazy ByteString.

If you define

import qualified Data.ByteString as S


strictToLazy :: S.ByteString -> L.ByteString
strictToLazy = L.fromChunks . return 

you can change your code fragment to

getSegmentParams :: Get (Int, L.ByteString)
getSegmentParams = do 
    seglen <- liftM fromIntegral getWord16be
    params <- getByteString (seglen - 2)
    return (seglen, strictToLazy params)

and all should be right with the world.

Edward Kmett
You don't need to convert to a Lazy ByteString - just get one directly via `getLazyByteString`. The haddock docs are great.
TomMD
That works too. =)
Edward Kmett
Quite true in this case. It's worth noting this is a distinctly different operation. Using `getByteString` when it isn't needed will force the entire `seglen` of bytes while `getLazyByteString` will remain lazy. Perhaps this is unimportant when the maximum size is 64kB, but if that were a `getWord32be` then you'd likely want the lazy behavior instead of potentially forcing a 32GB allocation.
TomMD
+4  A: 

It says you expect the second element of the tuple to be a L.ByteString (I assume that L is from Data.ByteString.Lazy) but the getByteString routine returns a strict ByteString from Data.ByteString. You probably want to use getLazyByteString.

TomMD