
Hi all, I'm writing a parser for a binary format, and I'm trying to debug it since I have a bug and the code is getting lost in the bits and bytes. Basically my main is like this: import Data.Binary.Get import Debug.Trace import qualified Data.ByteString.Lazy as L main = do bytes <- L.readFile "song.gp4" let (version, bytes') = getVersion bytes putStrLn version let stuff = runGet (getDocument version) bytes' putStrLn $ show stuff return () The getVersion and getDocument functions use the Data.Binary.Get monad to decode the byte string into various objects. I tried sprinkling "trace" calls a bit everywhere and I realize they don't always get called at the expected time. Most of them are only called when I reach the "putStrLn $ show stuff" statement. Unfortunately that doesn't help me because I get a *** Exception: too few bytes. Failed reading at byte position 35939 before that. Is this happening because I'm using lazy IO to read the file? Is there a way to force the evaluation of these "trace" calls? Are there any other ways to debug this kind of stuff in Haskell? Thanks a lot, Patrick -- ===================== Patrick LeBoutillier Rosemère, Québec, Canada

On Sunday 08 August 2010 19:14:41, Patrick LeBoutillier wrote:
Hi all,
I'm writing a parser for a binary format, and I'm trying to debug it since I have a bug and the code is getting lost in the bits and bytes. Basically my main is like this:
import Data.Binary.Get import Debug.Trace import qualified Data.ByteString.Lazy as L
main = do bytes <- L.readFile "song.gp4" let (version, bytes') = getVersion bytes putStrLn version
let stuff = runGet (getDocument version) bytes' putStrLn $ show stuff
putStrLn $ show stuff === print stuff
return ()
Unneeded
The getVersion and getDocument functions use the Data.Binary.Get monad to decode the byte string into various objects. I tried sprinkling "trace" calls a bit everywhere and I realize they don't always get called at the expected time.
trace prints its first argument when the second is demanded, so to print earlier, you can in general add more strictness to your programme, but I'm not sure if that makes a difference for Get, since that has no freedom to reorder the sequence in which the values are read. So with traces in the right places, you should get tracing output while the deserialisation is underway automatically. Whether in getSomeObject = do foo <- get !bar <- trace ("foo is " ++ show foo) get let !baz = trace ("bar is " ++ show bar) $ fiddle foo bar return $! trace ("baz is " ++ show baz) (wibble baz foo bar) the bangs make a difference regarding trace output, I don't know.
Most of them are only called when I reach the "putStrLn $ show stuff" statement. Unfortunately that doesn't help me because I get a
*** Exception: too few bytes. Failed reading at byte position 35939
before that.
That usually means the file hasn't the correct format, e.g. some size (length of list) has been written in little-endian order and is read in big-endian, so get tries to read more items than there are.
Is this happening because I'm using lazy IO to read the file?
Unlikely. What is the file size on disk? If it's larger than 35939 bytes, you have an IO problem, but still Data.ByteString.Lazy.readFile wouldn't be the first on my list of suspects.
Is there a way to force the evaluation of these "trace" calls?
Seeing more of the code could help coming up with ideas.
Are there any other ways to debug this kind of stuff in Haskell?
Break things down into smaller pieces and test those. And there's the ghci-debugger, I hear if one has learned to use it, it's quite helpful.
Thanks a lot,
Patrick

Hi,
I tried the bang patterns, it seems to force evaluation enough in most
cases to triger the "trace" call.
Thanks a lot,
Patrick
On Sun, Aug 8, 2010 at 2:18 PM, Daniel Fischer
On Sunday 08 August 2010 19:14:41, Patrick LeBoutillier wrote:
Hi all,
I'm writing a parser for a binary format, and I'm trying to debug it since I have a bug and the code is getting lost in the bits and bytes. Basically my main is like this:
import Data.Binary.Get import Debug.Trace import qualified Data.ByteString.Lazy as L
main = do bytes <- L.readFile "song.gp4" let (version, bytes') = getVersion bytes putStrLn version
let stuff = runGet (getDocument version) bytes' putStrLn $ show stuff
putStrLn $ show stuff === print stuff
return ()
Unneeded
The getVersion and getDocument functions use the Data.Binary.Get monad to decode the byte string into various objects. I tried sprinkling "trace" calls a bit everywhere and I realize they don't always get called at the expected time.
trace prints its first argument when the second is demanded, so to print earlier, you can in general add more strictness to your programme, but I'm not sure if that makes a difference for Get, since that has no freedom to reorder the sequence in which the values are read. So with traces in the right places, you should get tracing output while the deserialisation is underway automatically. Whether in
getSomeObject = do foo <- get !bar <- trace ("foo is " ++ show foo) get let !baz = trace ("bar is " ++ show bar) $ fiddle foo bar return $! trace ("baz is " ++ show baz) (wibble baz foo bar)
the bangs make a difference regarding trace output, I don't know.
Most of them are only called when I reach the "putStrLn $ show stuff" statement. Unfortunately that doesn't help me because I get a
*** Exception: too few bytes. Failed reading at byte position 35939
before that.
That usually means the file hasn't the correct format, e.g. some size (length of list) has been written in little-endian order and is read in big-endian, so get tries to read more items than there are.
Is this happening because I'm using lazy IO to read the file?
Unlikely. What is the file size on disk? If it's larger than 35939 bytes, you have an IO problem, but still Data.ByteString.Lazy.readFile wouldn't be the first on my list of suspects.
Is there a way to force the evaluation of these "trace" calls?
Seeing more of the code could help coming up with ideas.
Are there any other ways to debug this kind of stuff in Haskell?
Break things down into smaller pieces and test those. And there's the ghci-debugger, I hear if one has learned to use it, it's quite helpful.
Thanks a lot,
Patrick
-- ===================== Patrick LeBoutillier Rosemère, Québec, Canada

Excerpts from Patrick LeBoutillier's message of Sun Aug 08 13:14:41 -0400 2010:
The getVersion and getDocument functions use the Data.Binary.Get monad to decode the byte string into various objects. I tried sprinkling "trace" calls a bit everywhere and I realize they don't always get called at the expected time. Most of them are only called when I reach the "putStrLn $ show stuff" statement. [snip]
Is this happening because I'm using lazy IO to read the file? Is there a way to force the evaluation of these "trace" calls? Are there any other ways to debug this kind of stuff in Haskell?
To be more precise, this is happening because Haskell is processing the file lazily. My feeling is forcing the evaluation of the trace calls using seq or similar won't be too helpful, because your error is earlier than that, in your definition of the Get monad. If you trace in the monad before you exhaust the input stream, you should get useful info; the function getRemainingLazyByteString may also come in handy. Cheers, Edward
participants (3)
-
Daniel Fischer
-
Edward Z. Yang
-
Patrick LeBoutillier