How to print a Mathematica expression without evaluating it & how to use that for debugging.
Introduction
For easy debugging of larger functions I usually add the option debug->True
to output auxiliary variables.
A very easy approach would be the following:
myComplicatedFunction[arg1_, arg2_, (...), OptionsPattern[]]:=
Module[{(internalVariable, (...))},
(...)
If[OptionValue[debug],Print[internalVariable]];
(...)
];
this can be made a little bit shorter by wrapping the If
statement in a function
and adding something like deb=OptionValue[debug]
at the beginning of our function,
so that we can simply write
debugPrint[deb,interalVariable];
However, I would also like to automatically print the name of the variable, not just the value it has. That’s fairly easy, we simply put all arguments of our function on hold via
SetAttributes[debugPrint,HoldAll];
so that we can access the symbol name (as a string) inside of our debugPrint
function via
SymbolName@Unevaluated@expr
But with full expressions such as
debugPrint[deb,(internalVariable1+internalVariable2)/2]
we need to be more clever, because we cannot just use SymbolName@Unevaluated
to get a nice printable
expression: the expression is not a symbol (so SymbolName
won’t work) and simply using Print@Unevaluated@expr
will always
print out the Unevaluated
as well.
Here the trick is to use MakeBoxes
(which converts
everything into typesetting boxes that only contain strings) and then DisplayForm
to display that.
Code
Here’s the full code:
A small example to see how it can be used:
globalVar = 4;
complicatedFunction[OptionsPattern[]] :=
Module[{deb, a, b},
deb = OptionValue["debug"];
a = 1;
b = 2;
debugPrint[deb, "Debug enabled"];
debugPrint[deb, a];
debugPrint[deb, globalVar];
debugPrint[deb, a + b];
debugPrint[deb, (globalVar + b)/2];
Return["Whatever this function normally does..."];
];
Options[complicatedFunction] = {debug -> False};
And to run it:
(*should not print any debug messages*)
complicatedFunction[]
(*should print debug messages*)
complicatedFunction[debug->True]
Output:
Note how all local variables have an $4354
attached to make the variable name unique inside of Module
(mentioned e.g. here). In principle that suffix could
be stripped with a regular expression, but I think that it is valuable information whether we are dealing
with a local or global variable, so I just leave it like this.
Update (Jan 7 2018): Stripping the $...
suffix is now the default behaviour (which can be temporarily
disabled by an optional argument or by replacing removeDollars_:True
with removeDollars_:False
):
Stripping the suffix is implemented by first converting the expression to its FullForm
, which is then taken
as a string, so that we can simply use a regular expression to replace everything that starts with a dollar sign,
before converting it back to an expression.