This is mostly just a note to myself. Every time I get to the point in a project where I need to debug some Haskell code, I forget some of the more useful methods. I always seem to remember the printf-debugging method:

import Debug.Trace

debug = flip trace

f x = y `debug` (show y)

This one just prints out the String returned by show y when y is evaluated. This is useful for some bugs, but rarely for the kind that I seem to inflict upon myself.

The profiling infrastructure provides another axis for attacking problems:

These require compiling the program (and all of its dependencies) with profiling enabled. It is also useful to specify ghc-prof-options: -auto-all in your .cabal file to automatically annotate most values with names. These can help identify space leaks. Debugging stack overflows and <<loop>> errors is still difficult, since the -xc RTS flag doesn't give much of a stack trace.