But if you generate C code from Haskell, don't you have the same problem as before that it's difficult to reason about runtime characteristics due to laziness?
Not really. Haskell is basically used as a compiler from a DSL to C. Compilers running on general purpose systems are much less sensitive to timing and memory use than embedded systems and kernel drivers, so it isn't that big of a deal. The generated C code is the only thing that executes on the target device so you get the same performance that you would expect from C code.
The emitted code need not be lazy, and most often isn't. To a lesser extent the EDSL technique is also the technique that Accelerate uses to build fast array computations.