<div dir="ltr">I've been debugging some Haskell code, including a lot of work on Mutable Vectors, so naturally I've found `trace` useful, and in particular `traceM`, because it fits in nicely with monadic code. <div><br></div><div>The problem is that unlike `assert`, both `trace` and `traceM` execute unconditionally, I can't toggle them with a compiler flag.</div><div><br></div><div>I could however do something like this in every file I want to do tracing.</div><div><br></div><div>{-# LANGUAGE CPP #-}</div><div><br></div><div>#ifdef TRACE</div><div>trace = Debug.Trace.trace<br></div><div>traceM = Debug.Trace.traceM</div><div>#else<br></div><div>trace _ = id</div><div>traceM _ = pure ()</div><div>#endif</div><div><br></div><div>But already, that's a lot of boilerplate.</div><div><br></div><div>I'd also like to trace based on debug levels. For example, at TRACE level 2, only print trace statements at level 1 or 2, but at TRACE level 4, print trace statements at level 1, 2, 3 and 4, providing more detail (but more noise). </div><div><br></div><div>This makes the above code even more complex.</div><div><br></div><div>This wouldn't be a problem if I could put the code in a separate package, but I can't, as then whether tracing is on or not depends on the compiler settings of the tracing package, not on the calling package, which defeats the purpose somewhat.</div><div><br></div><div>I considered using implicit parameters to quietly pass whether I want tracing and at what level into the tracing module, but it seems to be that implicit parameters can't be defined at the top level.</div><div><br></div><div>It gets even more complex. When debugging, I might want to print something of type 'a'. Obviously 'a' will need some sort of show method for this to work, but outside of debug mode I don't want to restrict my function's types to things which are showable. So I considered doing this:</div><div><br></div><div>#ifdef TRACE</div><div>type DebugShow a = Show a</div><div>debugShow = show</div><div>#else<br></div><div>type DebugShow a = ()</div><div>debugShow _ = error "DEBUG SHOWING OUTSIDE OF DEBUG MODE"</div><div>#endif</div><div><br></div><div>And of course, if you're only using `debugShow` as part of an argument to `trace`, lazy evaluation will avoid `debugShow` ever being called when tracing is not enabled.</div><div><br></div><div>But put all this together and you've got around a dozen lines of boilerplate just to do tracing, without even having tracing levels yet, that have to be put in every module you want to use tracing, but don't want a whole lot of debug data being spat out in a release compile.</div><div><br></div><div>Also, adding any other tracing functions just makes this longer.</div><div><br></div><div>The only approach I can think of so far is to whack this all in a template haskell module and add code that splices it all into the current module:</div><div><br></div><div>e.g.</div><div><br></div><div>#ifdef TRACE</div><div>$(traceFunctions True)</div><div>#else</div><div>$(traceFunctions False)</div><div>#endif</div><div><br></div><div>Where `traceFunctions` is a template haskell function that dumps all the appropriate functions and type definitions mentioned above (and maybe more) at the top level of the calling module.</div><div><br></div><div>So my questions are:</div><div><br></div><div>1. Is there a better way? And</div><div>2. Has this problem already been solved?</div></div>