Laziness in Haskell is so hard for me to understand. I never have any idea what the runtime performance of something I write in Haskell will be. It's either blazingly fast or molasses slow, and I can never tell.
Avoid String, use Text or ByteString. Avoid [] for data processing, prefer Vector. Avoid lazy IO, use Conduit (or similar). Prefer newtype to data, and make data fields strict where appropriate. Make sure you're building with -O2 (has to be explicit, none of the tooling enables it by default).
These rules cut out 99% of space leaks. The profiling tools are a big help for the last 1%.