<div dir="ltr"><div>PS: adding a new monad transformer to the monad stack just to add log capacity seems overkill.<br></div>what do you guys think?<br><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Nov 22, 2016 at 3:58 PM, Corentin Dupont <span dir="ltr"><<a href="mailto:corentin.dupont@gmail.com" target="_blank">corentin.dupont@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div><div><div><div><br></div>Hi Clinton,<br></div>I've been running into the same problem recently: regularly adding and then removing a lot of traces from my code.<br></div><br>Personally I don't like adding conditional compilation/cpp in my code (it's quite ugly and difficult to maintain).<br>I've been looking into a logging packages: <a href="https://hackage.haskell.org/package/tinylog-0.14.0/candidate/docs/System-Logger.html" target="_blank">https://hackage.haskell.org/<wbr>package/tinylog-0.14.0/<wbr>candidate/docs/System-Logger.<wbr>html</a><br><br></div>The question is: how to carry around the settings of the logger (i.e. the log levels: Warn, Fatal...) in your program?<br></div>I usually structure my programs around a big State monad, that I access using Lenses. The log level could be added there.<br><br><div><div><br><br><br></div></div></div><div class="gmail_extra"><br><div class="gmail_quote"><div><div class="h5">On Tue, Nov 22, 2016 at 2:37 PM, Clinton Mead <span dir="ltr"><<a href="mailto:clintonmead@gmail.com" target="_blank">clintonmead@gmail.com</a>></span> wrote:<br></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5"><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>
<br></div></div><span class="">______________________________<wbr>_________________<br>
Haskell-Cafe mailing list<br>
To (un)subscribe, modify options or view archives go to:<br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bi<wbr>n/mailman/listinfo/haskell-caf<wbr>e</a><br>
Only members subscribed via the mailman list are allowed to post.<br></span></blockquote></div><br></div>
</blockquote></div><br></div>