[Haskell-cafe] Debug tracing in Haskell
Simon Michael
simon at joyful.com
Tue Nov 22 15:52:51 UTC 2016
Hi Clinton,
at
http://hackage.haskell.org/package/hledger-lib-1.0.1/docs/Hledger-Utils-Debug.html
you can see an approach using unsafePerformIO.
This lets me invoke programs with --debug[=1..9] to get progressively
more debug output.
It seems to work for me, see what you think..
On 11/22/16 5:37 AM, Clinton Mead wrote:
> 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.
>
> The problem is that unlike `assert`, both `trace` and `traceM` execute
> unconditionally, I can't toggle them with a compiler flag.
>
> I could however do something like this in every file I want to do tracing.
>
> {-# LANGUAGE CPP #-}
>
> #ifdef TRACE
> trace = Debug.Trace.trace
> traceM = Debug.Trace.traceM
> #else
> trace _ = id
> traceM _ = pure ()
> #endif
>
> But already, that's a lot of boilerplate.
>
> 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).
>
> This makes the above code even more complex.
>
> 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.
>
> 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.
>
> 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:
>
> #ifdef TRACE
> type DebugShow a = Show a
> debugShow = show
> #else
> type DebugShow a = ()
> debugShow _ = error "DEBUG SHOWING OUTSIDE OF DEBUG MODE"
> #endif
>
> 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.
>
> 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.
>
> Also, adding any other tracing functions just makes this longer.
>
> 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:
>
> e.g.
>
> #ifdef TRACE
> $(traceFunctions True)
> #else
> $(traceFunctions False)
> #endif
>
> 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.
>
> So my questions are:
>
> 1. Is there a better way? And
> 2. Has this problem already been solved?
>
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> Only members subscribed via the mailman list are allowed to post.
More information about the Haskell-Cafe
mailing list