Re: Re: problem writing debugging utility function
- To: mathgroup at smc.vnet.net
- Subject: [mg100371] Re: [mg100308] Re: problem writing debugging utility function
- From: Leonid Shifrin <lshifr at gmail.com>
- Date: Tue, 2 Jun 2009 06:42:45 -0400 (EDT)
- References: <gvq09k$mqv$1@smc.vnet.net> <200905311037.GAA17048@smc.vnet.net>
Hi, Just to add some more to the reply of Szabolcs: The evaluation process in Mathematica is recursive, going first "down" to leaves, then evaluating it "up", starting from leaves and going to larger sub-expressions, checking for the global rules to match. Unevaluated is treated in a special way in that it suppresses the evaluation of expression "on the way down", allowing the rules attached to the head (say <g>) surrounding it to apply "on the way up" on the original expression. The original expression may or may not evaluate later, depending on what <g> does with its argument. In the following example: In[1] = g[x_ + y_] := x*y; g[Unevaluated[5 + 5]] Out[1] = 25, the rule attached to <g> did apply since the expression 5+5 was preserved in its unevaluated form. In this case, the original expression (Plus operator) never evaluated, but in some other cases it may evaluate - it all depends on <g> now. But without Unevaluated, <g> would never have a chance to see the original expression, since by the time evaluation goes "up" to g, 5+5 would have evaluated to 10 already. This situation indeed is precisely as if we would give <g> Hold attribute "on the way down" and remove it "on the way up". There are several differences between Hold and Unevaluated. Technically, Hold is just a wrapper with a HoldAll attribute which is not particularly different from any user-defined HoldAll wrapper, and is special just because it is the "official" holding wrapper and there are commands such as ReleaseHold that work with it together. Most of the functionality of Hold can pretty much be duplicated/reproduced by any HoldAll wrapper. OTOH, Unevaluated is one of the "magic symbols", along with Evaluate and Sequence. It is more deeply "wired in", into the main evaluation loop algorithm, and its functionality can not be removed, blocked or duplicated. In particular, we may block Hold with a Block trick Block[{Hold},...], but we can not block Unevaluated in the same way. Another difference is that (one level of wrapping with) Unevaluated does not by itself represent extra level of wrapping - it is automatically stripped off when the evaluator comes to apply the rules to expression inside it. Not so with Hold - it is a normal wrapper. >From the viewpoint of the user, the uses of Hold and Unevaluated are also different. Hold is often used to preserve the internal expression unevaluated for more than one successive evaluation (or in between such evaluations). For example, if one function (say <f>) produces the result as an expression which wil normally evaluate but whose evaluation we want to prevent, and another function (say <h>) needs to consume this result in this unevaluated form, but the result is not passed directly from <f> to <h>, then <f> may wrap the result in Hold and <h> will then have to unwrap it. Unevaluated would not help us here since it is normally used in a single evaluation. Here is a simple example: In[2] = Clear[f,h]; f[x_] := Module[{y}, y = Hold[x^2]]; h[x_Hold] := x /. Hold[a_^b_] :> {a, b} In[3] = odd = Select[f /@ Range[10], Not[FreeQ[#, _?OddQ]] &] Out[3] = {Hold[1^2], Hold[3^2], Hold[5^2], Hold[7^2], Hold[9^2]} In[4] = h /@ odd Out[4] = {{1, 2}, {3, 2}, {5, 2}, {7, 2}, {9, 2}} What happens here is that <f> constructs some power (square) while <h> deconstructs it to base-power pair. But <h> is not called directly on the result of <f>, so we need to prevent expressions from evaluation in between evaluations involving <f> and <h>. Unevaluated would not be helpful here. Another thing worth mentioning (and more directly relevant to your example) is the mechanics of argument - passing. Consider this function: In[5] = Clear[f]; f[x_] := {Hold[x],Head[x]}; It is supposed to return the held input together with its head . Let us try In[6] = (Print["Just before calling f"]; f[#]) &[Print["*"]] * Just before calling f Out[6]= {Hold[Null],Symbol} If we attempt to force it to not evaluate the argument (Printing), in this way: In[7] = Function[y, (Print["Just before calling f"]; f[y]), HoldAll][Print["*"]] Just before calling f * Out[7]= {Hold[Null],Symbol} We see that the result was indeed not evaluated before having been passed to <f>, but it was evaluated in <f>, and the r.h.s of <f> uses an already evaluated result. Now, it is to prevent also this evaluation of the argument that we need Unevaluated: In[8] = Function[y, (Print["Just before calling f"]; f[Unevaluated[y]]), HoldAll][Print["*"]] Just before calling f * Out[8] = {Hold[Print["*"]], Symbol} We see that the printing still takes place, and while the held part is ok, the head part still computes the Head of the evaluated argument (that's where the printing happens). This is because this time, Head needs Unevaluated - we redefine <f>: In[9] = Clear[f]; f[x_] := {Hold[x],Head[Unevaluated[x]]}; In[10] = Function[y, (Print["Just before calling f"]; f[Unevaluated[y]]), HoldAll][Print["*"]] Just before calling f Out[10]= {Hold[Print[*]],Print} Now we get what we want. Hopefully by this moment the pattern started to emerge. Note that Unevaluated is unnecessary if the function itself holds its argument, possessing one of the hold attributes: In[11]= ClearAll[f]; Attributes[f] = {HoldAll}; f[x_] := {Hold[x], Head[Unevaluated[x]]}; In[12] = Function[y, (Print["Just before calling f"]; f[y]), HoldAll][Print["*"]] Just before calling f Out[12]= {Hold[Print[*]],Print} It is slightly off the main line of the argument, but another common pitfall associated with this sort of things is something like this: In[13] = {Hold[#] &[5^2],Hold[5^2]} Out[13] = {Hold[25],Hold[5^2]} The #-& notation is so routinely used that one often forgets that it does introduce an additional parameter-passing stage. This is what one should use to avoid evaluation during that stage: In[14] = {Function[Null, Hold[#], HoldAll][5^2], Hold[5^2]} Out[14] = {Hold[5^2], Hold[5^2]} Sometimes the opposite is needed however: In[15]:= i = 0; Function[x, {x, x, x}, HoldAll][i++] Out[15]= {0, 1, 2} In[16] = i Out[16] = 3 In[17]:= i = 0; Function[x, {x, x, x][i++] Out[17]= {0, 0, 0} In[18] = i Out[18] = 1 In this case, chances are that the first behavior is not what was intended. So, to summarize: Hold is mostly useful to prevent evaluation of some results, in between some other evaluations. Unevaluated in useful to force some function use - just once, in this particular evaluation (for its r.h.s.) - its original (unevaluated) argument if that function does not have a corresponding hold attribute. Hold attributes are useful for the same thing, but 1) They are permanent, not just one-time use 2) Unevaluated wrappers are stripped off when evaluator meets them "on the way up", so subsequent evaluation uses already normal version of the argument - not so with attributes 3) You may need to work with functions written by others (or system functions), for which changing attributes even temporarily may have undesired/unpredictable consequences - in this case Unevaluated is more appropriate, to make up for the lacking hold attribute just once. Perhaps, another way to put is is that attributes belong to the function, while Unevaluated "belongs" to a particular argument (though affecting the execution of the function on that argument as if that function had a hold attribute). This is probably a very long-winded way to explain these things, but I hope it will still clarify some issues. Best regards, Leonid On Sun, May 31, 2009 at 3:37 AM, dabrowsa at indiana.edu <dabrowsa at indiana.edu>wrote: > Thanks a lot to Leonid, Szabolcs, and Ken for their solutions. I > liked Leonid's the best, being both much simpler and more general than > mine. > > SetAttributes[ShowIt, HoldAll]; > ShowIt[code_] := > Module[{y}, > Print[ToString[Unevaluated[code]], " = ", y = code]; > y]; > > My own solution was the hideous > > $PreRead=ReplaceAll[#,{{"dbgv","[",var_,"]"}:>{"Print","[",RowBox > [{"\""<>var<>" = "<>"\"",",",var}],"]"}}]&; > > which makes dbgv work like a macro. The grotesqueness is because what > $PreRead sees is a very raw input form, with expressions broken down > into RowBox's. In a sense this is the most direct analog to Lisp's > macros, but ... yechh. > > The Unevaluated[] function had slipped off my radar, probably because > I never fully grokked the distinction between it and Hold[]. In fact > I'm still a bit confused about it. At first I thought it might like > the evaluation inhibitor ` in Lisp, but some examples disabused me of > that. > > In[2]:= f@Unevaluated[5 + 6 + 7 + 8] > > Out[2]= f[Unevaluated[5 + 6 + 7 + 8]] > > In[11]:= ToString@Unevaluated[5 + 6 + 7 + 8] > > Out[11]= "5 + 6 + 7 + 8" > > > I might have expected Out[11]= "Unevaluated[5 + 6 + 7 + 8]" > > > In[13]:= sqr[x_] := x^2 > > In[14]:= sqr@Unevaluated[5 + 6 + 7 + 8] > > Out[14]= 676 > > > I might have expected Out[14]= sqr[5 + 6 + 7 + 8] since sqr does not > know what to do with the pattern _+_+_+_ or _+_ for that matter. > Could anyone elucidate this for me? >