Ive got two two functions which act on byte strings. The first one is a bytestring version of the cycle function in Data.List and the second function rotates the bytestring.
When I read a file and send its input to the rotateBytes function, it outputs a quotation mark and then I need to press Control-C to manually stop the function. Is this a bug in my code or a bug in ghc? How can it be fixed?
import qualified Data.ByteString as B
-- Cycle function for binary data
cycleBytes :: B.ByteString -> B.ByteString
cycleBytes xs
| B.null xs = error "cycleBytes: empty list"
| otherwise = xs' where xs' = xs `B.append` xs'
-- Rotate function for binary data
rotateBytes :: B.ByteString -> Int -> B.ByteString
rotateBytes xs n = B.take (B.length xs) $! B.drop (B.length xs + n) $! cycleBytes xs
Using the function is currently like this:
*Main> B.readFile "test.dat" >>= (\x -> return $ rotateBytes x 3)
"
^CInterrupted.
ByteString isn’t lazy so can’t cope with the infinite answer from
cycleBytes. (The"you’re getting is because when printing the result, it can lazily get the first character of output without worrying about the rest, but then tries to calculate the infinite ByteString it gets fromcycleBytesbefore printing anything else. Infinity and strict evaluation don’t mix.)Data.ByteString.Lazyinstead (and usefromIntegralon yourn, because it wantsInt64notInt; You might want to use Lazy ByteStrings for enormous amounts of data, so you the library needs a length parameter that allows this.)nmodB.length xsand just useB.append xs xsinstead of infinitely many.Solution 1 looks like
If
test.datcontainedHello Mum!this would calculateChunk "lo Mum!" (Chunk "Hel" Empty), because it’s lazily constructed and will only get combined if it’s forced.Solution 2 looks like
Solution 2 is better partly because you get to keep everything strict (which I assume you were trying to do), but doesn’t have
cycleBytes.Ben Millwood suggests replacing this with something along the lines of
which reads more clearly.
take,dropandsplitAtare all O(1) inByteString, so it doesn’t make much difference for efficiency, but thesplitAtdoes feel cleaner.