Re: Re-evaluation of Conditional expressions
- To: mathgroup at smc.vnet.net
- Subject: [mg3512] Re: Re-evaluation of Conditional expressions
- From: withoff (David Withoff)
- Date: Mon, 18 Mar 1996 01:00:02 -0500
- Organization: Wolfram Research, Inc.
- Sender: owner-wri-mathgroup at wolfram.com
Judging from the number of responses to the "Re-evaluation of Conditional expressions" message, my initial one-paragraph explanation was clearly inadequate. I'm sorry if my explanation generated more confusion than it resolved. I was originally thinking that this was just a problem with the meaning of Update, but apparently, at least for some, there was also a problem with the much more fundamental question of when and why expression elements are held unevaluated, and the effect that this has on results. There are four related things that came up in this discussion that I would like to comment on: 1) The role of the HoldAll attribute. In my intial explanation, I neglected to mention the HoldAll attribute. Dave Wagner has already explained why If needs to at least have the HoldRest attribute: if the second and subsequent elements in If[cond, e1, e2, e3] were not held unevaluated, they would be processed regardless of the value of cond. This would defeat the purpose of the If statement, which is to select only one of the evaluations. 2) Whether or not If needs to hold the first element unevaluated. As Dave Wagner pointed out, the explanation in (1) does not resolve the question of whether or not the first element in If should be held unevaluated. I am not aware of any overwhelming design objective to decide this issue, and can easily come up with examples in which you would want the first element in If to be evaluated, and examples in which you would not want the first element to be evaluated. For reasons that I could elaborate upon separately, I am currently leaning in favor of not holding the first element in If unevaluated. This can be achieved by setting the HoldRest attribute for If, rather than the HoldAll attribute. (In the vast majority of practical programs, it doesn't make any difference.) 3) Use of a delayed assignment does not change the original example As a reminder, here is the initial example. In[1]:= y = If[x, 1, 2] Out[1]= If[x, 1, 2] In[2]:= x = z Out[2]= z In[3]:= y Out[3]= If[x, 1, 2] In[4]:= z = True Out[4]= True In[5]:= y Out[5]= If[x, 1, 2] <==== a result of 1 was expected here. If you try this example using a delayed assignment (y := If[x, 1, 2]) the behavior will be essentially unchanged. The expression If[x, 1, 2] evaluates to itself in In[3], and will not be re-evaluated unless something inside the expression changes. The use of a delayed assignment prevents the initial evaluation of If[x, 1, 2] during evaluation of the assignment y = If[x, 1, 2], but does not otherwise change the example. 4) The effect of replacing the HoldAll attribute with HoldRest Replacing the HoldAll attribute of If with HoldRest may be the easiest way to get the behavior that was expected in the first place. In[1]:= ClearAttributes[If, HoldAll]; SetAttributes[If, HoldRest] In[2]:= y = If[x, 1, 2] Out[2]= If[x, 1, 2] In[3]:= x = z Out[3]= z In[4]:= y Out[4]= If[z, 1, 2] In[5]:= z = True Out[5]= True In[6]:= y Out[6]= 1 Here, If[x, 1, 2] does not evaluate to itself. After the assignment to x, it evaluates to If[z, 1, 2]. The subsequent change in the value of z causes yet another evaluation, since this time, something explicitly present in the expression changed (the value of z). I hope that this last point answers the most immediate concerns that Richard Fateman raised about my explanation. Specifically, the change when "If" is replaced by "f" is a consequence of the fact that "f" doesn't by default hold its elements unevaluated. If you set the HoldAll attribute for f, and add a rule that causes f to do something when its first element evaluates to True or False, the behavior will be identical in this example to the behavior of If. In[1]:= SetAttributes[f, HoldAll] In[2]:= f[cond_, e1_, e2_] := e1 /; cond === True In[3]:= f[cond_, e1_, e2_] := e2 /; cond === False In[4]:= y=f[z,1,2] Out[4]= f[z, 1, 2] In[5]:= z=True;y Out[5]= 1 In[6]:= z=ww;y Out[6]= f[z, 1, 2] Finally, here is a non-technical, somewhat personal note. Richard Fateman's remark that "evaluation in Mathematica is rather subtle" brought back bad memories for me of my time in academia, only this time, to my embarassment, I'm afraid that I (and others at Wolfram Research) are the teacher. The bad memory is that most of the time when a teacher said that something was "subtle" it meant either that the teacher didn't understand it well enough to explain it clearly, or couldn't be bothered to explain it clearly. Well, we really do understand this aspect of Mathematica, and it's pretty straightforward. It would be a shame if anyone was left with the idea that this material is complicated just because no one bothered to explain it. The explanation in the Mathematica book (especially the section on evaluation in the appendix) is, I think, pretty good, but that of course doesn't mean that there won't ever be any questions about it. If there are any remaining questions, please let me know. Dave Withoff Research and Development Wolfram Research ==== [MESSAGE SEPARATOR] ====