MathGroup Archive 2009

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: problem writing debugging utility function

  • To: mathgroup at smc.vnet.net
  • Subject: [mg100273] Re: [mg100248] problem writing debugging utility function
  • From: Leonid Shifrin <lshifr at gmail.com>
  • Date: Sun, 31 May 2009 06:30:53 -0400 (EDT)
  • References: <200905300057.UAA23426@smc.vnet.net>

Hi,

the way to do it is to use non-standard evaluation. Here is the function
that probably does what you want

In[1] =

SetAttributes[ShowIt, HoldAll];
ShowIt[code_] :=
  Module[{y},
   Print[ToString[Unevaluated[code]], " = ", y = code];
   y];

This will print the variable name, its value, and then return the variable
value itself so that you can use it in your code, just as before - you just
need to "stick" ShowIt in the place where you need to print the info.  The
parameter of the function does not necessarily have to be a variable - you
can wrap it around any piece of code (there could be a few subtleties if
your code also uses non-standard evaluation, but this is rarely the case).
Note that we take care that the code (<code>) is executed only once, so the
case of  side effects (like i++ etc) is handled correctly. Example:

In[2] =
Block[{i, res = Table[0, {5}]},
 For[i = 1, i <= 5, i++,
  res[[i]] = ShowIt[i]];
 res]

i = 1
i = 2
i = 3
i = 4
i = 5

Out[2] = {1,2,3,4,5}


 >But it's worth
>noting that this would trivial to solve with a Lisp macro, and despite
>the fantastic expressibility of Mathematica it doesn't seem to have a
>good replacement for macros.

This is just not true. The ShowIt function above *is* a macro, since, due to
the HoldAll attribute, it expands the code before it is run. As another very
simple macro example, consider this:

ClearAll[withCodeAfter];
SetAttributes[withCodeAfter,HoldRest];
withCodeAfter[before_,after_]:=(after;before);

This macro can be used to avoid an introduciton of auxilliary variable in
case
when the result is computed somewhere in the middle of the code (by the
<before> piece), but when some other code must be executed (<after> piece),
before the result is returned. Example:

In[3] =
Clear[i];
i = 0;
withCodeAfter[Print[i], i++]

0

In[4] = i

Out[4] = 1


The availability of macros in Mathematica is apparent from the fact that all
the code we write is data as well (as can be seen by the FullForm command),
and the availability of non-standard evaluation. This fact is obscured by
the built-in pretty-printer/preprocessor which allows us to use shortcut and
infix notation.

However indeed there are a few reasons that make macros harder to write in
Mathematica:

a) Evaluator is more complex, than in Lisp. There are several kinds of
global rules, there are attributes, there are several ways to make
evaluation non-standard, there are built-in rules for system functions that
the user may not be aware of, there is dynamic scoping with Block that is
very powerful but can be easily abused, there are several lexical scoping
constructs (Module, With, Function, SetDelayed, etc) and associated with
them rules for variable collision resolution, etc, etc. It is harder to
"compute" the consequences of the macro expansion, or to get it right in all
cases of intended use.

b) Pattern-matching gets in the way when some portion of the code is
rule-based, since evaluation depends on whether or not some patterns match.

c) This is a consequence of b): when we define a function with restricted
patterns such as f[x_Integer]:=... etc, we effectively introduce a (weak)
typing,
which also gets in the way.

d) It requires conscious effort not to use (at all) short-hand and/or infix
notation, which is handy but often hides that the code may expressed as an
expansion of some macro.

I think it will generally be  very nice if macros would find their way into
the mainstream Mathematica programming, but this will probably start to
really pay off for those who  intend to use Mathematica to  build  rather
large/complex systems (or their prototypes).

Best regards,
Leonid


On Fri, May 29, 2009 at 5:57 PM, dabrowsa at indiana.edu
<dabrowsa at indiana.edu>wrote:

> This matter is pretty unimportant, but perhaps of interest in laying
> out a persistent source confusion for me with Mathematica: evaluation
> control.
>
> I'm skeptical of the built-in debugger because it seems to crash the
> kernel often, so I do most of my debugging by inserting print
> statements like
>
>    Print["variableOne = ",variableOne].
>
> Being extraordinarily lazy I soon thought it might be nice to have a
> little function, say dbgv, which takes a variable or name of a
> variable as an argument, and produces the same result as the print
> statement above.
>
> At first I assumed this would be easy, since almost every programming
> problem turns out to be pretty easy with Mathematica.  But after an hour
> or so I began to wonder whether it would be possible at all.  I did
> eventually find a solution, a function dbgv such that dbgv[variableOne]
> produces exactly the effect of the print statement, but it's really ugly.
> I'll post it later.
>
> Granted this is not an important problem since it's not too much
> trouble to just type in the whole print statement.  But it's worth
> noting that this would trivial to solve with a Lisp macro, and despite
> the fantastic expressibility of Mathematica it doesn't seem to have a
> good replacement for macros.  The closest equivalents are $Pre(Read),
> which I used in my solution, but they're not nearly as nice to work with.
>
> Can anyone think of an elegant solution?
>
>


  • Prev by Date: Re: Image[], Graphics[Raster[]]
  • Next by Date: Re: RandomReal gets stuck
  • Previous by thread: Re: problem writing debugging utility function
  • Next by thread: Re: problem writing debugging utility function