[Haskell-cafe] Architecturally flawed

Don Stewart dons at galois.com
Thu Jul 10 14:41:45 EDT 2008

> I could try GHC's new debugger. But my experiences with it so far have 
> shown that for all but the most trivial programs possible, it becomes 
> intractably difficult to figure out what the debugger is actually 
> showing you. I actually tried to debug a "normal" LZW implementation 
> once - one that didn't involve two highly convoluted custom monads and a 
> stateful execution model with manually threaded state. This is *not* my 
> idea of a fun time...

For what its worth, people are using this at work on large projects
> In a "normal" programming language, at this point you would sprinkle a 
> few print statements around so you can see the intermediate steps the 
> program is taking. But I can't. I'm in the wrong monad. Curses!

Use Debug.Trace.trace.
> In the end, the only solution I could come up with was to design a 
> second, "hacked" version of the two monads. Instead of importing one 
> module, you import another that provides the same interface. However, 
> now Reader and Writer are aliases to IO. All write requests cause 
> pretty-printed binary to be sent to stdout, and all read requests pop up 
> a prompt for input from stdin. It worked reasonably well in that I could 
> now add the vitally necessary print statements, and see intermediate 
> values and so forth... It wasn't very pretty though.

You should have used Debug.Trace.
> So at least I got that part fixed. Heh. But now I find myself worrying 
> about yet *another* problem: is Writer lazy enough?
> I mean, the idea is that you can write a program that lazily reads from 
> a file, pushes it through a Writer, and lazily writes the result back to 
> another file. The thing should chug along reasonably fast and use a 
> constant amount of RAM. But all this is only true of Writer is actually 
> lazy enough. I have a horrible feeling that all the complicated Origami 
> inside makes it too strict. And I have no way to check!

Actually, you can use 'chasingBottoms' to write QuickCheck properties
that state your expected laziness or strictness behaviour.
> Actually, thinking about it, is Reader lazy enough? You call run_reader 
> and it hands over your data, but if that data is, say, a list, will 
> run_reader build the entire damn list before it'll hand it over? Or will 
> the monadic code by called as-needed to generate the list elements? 
> Obviously I desire the latter, but I'm really not sure what the actual 
> behaviour is...

The mtl Reader class is lazy.
> In summary, I've spent several days coding, and I still don't have a 
> single algorithm working. I've spent all my time wrestling with the 
> mundane details of infrastructure rather than the interesting algorithms 
> I actually set out to implement. This makes me very sad. :-(

You should have stopped by #haskell a few days ago.
> If anybody can think of a better set of abstractions or another way to 
> do debugging, I'd be interested to hear about it.

There's already a bit layer for Data.Binary on hackage, for what its
worth. And an LZW encoder/decoder.
> (This would all be so trivial in an OO language. Just make an Encoder 
> object that updates its own state internally and talks to a Source 
> object and a Destination object for its data...)

Make an Encoder class that updates its own state internally and lazy
streams input and output. As Data.Binary does, as zlib does, et al.

-- Don

More information about the Haskell-Cafe mailing list