One thing I haven’t seen mentioned here yet: I use print debugging all the time in Haskell, and find it works really well there compared to other languages. There’s a couple of reasons for this, I think:
• Nearly everything is immutable, so once I print the value of an expression I know it won’t change in the future. This is not the case in other programming languages, where a variable can be mutated after I print it.
• The base library provides a really nice range of functions for print debugging [0] — so I can just wrap any expression I want printed in ‘traceShowId’, and it’ll get printed. (Yes, these functions break purity; that’s why the module is marked ‘Debug’!)
Of course, sometimes print debugging isn’t sufficient, in which case I fire up the GHCi stepper debugger. But for the vast majority of cases print debugging works well.
[0] https://hackage.haskell.org/package/base-4.15.0.0/docs/Debug...