Re: Re: Re: Mathematica language issues
- To: mathgroup at smc.vnet.net
- Subject: [mg53112] Re: [mg53050] Re: Re: Mathematica language issues
- From: "Fred Simons" <f.h.simons at tue.nl>
- Date: Fri, 24 Dec 2004 05:58:58 -0500 (EST)
- Sender: owner-wri-mathgroup at wolfram.com
So far I could resist the temptation to participate in this discussion. However, in his mail Maxim Rytin presents some examples of which he thinks the result is unpredictable. Maybe there is some interest in how I predict the results of simple commands in which Unevaluated occurs. Of course these examples are of no practical interest. Unevaluated is meant to pass unevaluated arguments to a function body and as such it works perfectly. No one in practice is interested in (1+1)*Unevaluated[2+2]. The basic principle has been clearly explained by Andrzej Kozlowsky. Suppose we have a function f that we call with one or more Unevaluated arguments. The first step in the evaluation procedure is that arguments are evaluated as far as allowed and attributes such as Orderless and Flat are applied. In this step Unevaluated is unwrapped from the argument, but Mathematica has labeled the arguments which come from Unevaluated. If now no rules for f can be applied, Mathematica returns the result so far, with Unevaluated wrapped again around the labeled arguments. If a rule for f can be applied, the administration of arguments that come from Unevaluated is completely skipped. Here are three illustrative examples. Try to predict the result! In[1] := ClearAll[f] Attributes[f]={Orderless}; f[b, Unevaluated[a]] // Trace Out[3]= {f[b,a],f[a,b],f[Unevaluated[a],b]} In[4]:= ClearAll[f] Attributes[f]={Orderless}; f[x__]:= {x}[[1]]; f[b, Unevaluated[a]] // Trace Out[7]= {f[b,a],f[a,b],{a,b}[[1]],a} In[8]:= ClearAll[f] Attributes[f]={Orderless, Flat}; f[b, Unevaluated[f[a,c]]] // Trace Out[10]= {f[b,f[a,c]],f[b,a,c],f[a,b,c],f[Unevaluated[a],b,Unevaluated[c]]} The second example equals the first example, but now a rule for f is applied so the result is a instead of Unevaluated[a]. The third example demonstrates the labeling: the arguments a and c come from an Unevaluated argument in the function call. Since no rule for f is applied, they are wrapped with Unevaluated in the result, which is rather different from the original command. With respect to the functions Plus and Times the results seem to different. When we consider e.g. Times[Unevaluated[z], 2], we expect that in the first step of the evaluation due to the attribute Orderless of Times we arrive at Times[2, z] with z labeled as coming from an Unevaluated argument. Since no rules for Times can be applied, we expect the result to be 2*Unevaluated[z]. But the result is 2*z. In order to understand what is going on here, we must have a closer look at the functions Plus and Times. I first formulate my assumption (only WRI and maybe a few others know if I am right!) and then I will explain and demonstrate it by some examples. Finally, using this hypothesis I will explain Maxim's counterexamples. Hypothesis: When Mathematica has to evaluate an expression with head Plus or Times, then immediately after the evaluation of the head, so before the use of the attributes, Mathematica calls a function that adds or multiplies all numerical arguments. If there are no other arguments, this result is the outcome of the evaluation. Otherwise Plus or Times is called with this numerical result as first argument followed by the remaining arguments. To illustrate the hypothesis we slightly modify the function Plus (the same can be done with Times) so that Mathematica tells us when and how Plus is called during the evaluation. Moreover, and that can be dangerous, we remove the attribute Orderless of Plus. In[13]:= Unprotect[Plus]; Attributes[Plus]= Complement[Attributes[Plus], {Orderless}]; Plus[x___] /; (Print["Plus"[x]];False) := 12 In[16]:= 3 + c - 5 + b - a + 6 From In[16]:= Plus[4,c,b,-a] Out[16]= 4+c+b-a In[17]:= 2-5+10 Out[17]= 7 In the first example we see from the printed message that the first time Plus is called all numerical arguments are already added, the remaining arguments are not sorted. In the second example we see that Plus is not called at all. That indeed Mathematica automatically calls another function when an expression with head Plus or Times is met can be seen from the following example, for which we start with a fresh kernel. In[18]:= Quit[] In[1]:= Block[{Plus}, Plus[a__]:= {a}[[1]]; {Plus[x,1], Plus[1+12], Plus[12,x,-12]}] Out[1]= {1,13,x} Despite the fact that within the block we have a local variable Plus with a very different definition of the outside function Plus, the pre-evaluation mentioned in the hypothesis takes place! (I do not consider this as a bug in scoping but as a feature of the system names Plus and Times). So let us accept the hypothesis, let PrePlus and PreTimes be our names for the functions mentioned in the hypothesis and let us consider some example's of the type of Maxim's counterexamples. 1. Times[Unevaluated[z], 2]. PreTimes[Unevaluated[z], 2] applies a rule for PreTimes, so the labeling of arguments from Unevaluated disappears and we arrive at Times[2, z] with z not wrapped by Unevaluated. 2. 1 + 1 + Unevaluated[z]. PrePlus[1,1,Unevaluated[z]] applies a rule to arrive at Plus[2, z], so z is not wrapped with Unevaluated. 3. 2 + Unevaluated[z]. PrePlus[2, Unevaluated[z]] has no rules to apply so we arrive at Plus[2, z] with z still marked as coming from an Unevaluated argument, so the result is Plus[2, Unevaluated[z]] (a different result from the previous example!) 4. Unevaluated[2]/Sqrt[2]. PreTimes does not apply a rule, so we arrive at Times[2, 1/Sqrt[2]] with the first argument still marked. Now Times applies a rule and the result has no Unevaluated arguments. 5. Unevaluated[Sqrt[2] + Sqrt[2]]/Sqrt[2]. PreTimes does not apply a rule, so we arrive at Times[1/Sqrt[2], Sqrt[2]+Sqrt[2]] with the second argument labeled. Times has no rules for these arguments, so the outcome is Unevaluated[Sqrt[2] + Sqrt[2]]/Sqrt[2]. 6. Unevaluated[Sqrt[2]*(Sqrt[3] + 1)]*Csc[Pi/12]. PreTimes does not apply a rule so due to the attribute Flat of Times we arrive at Times[Sqrt[2], Sqrt[3] + 1, 1 + Sqrt[3], Sqrt[2]], where the first two arguments are labeled. Mathematica 5.1 now returns Sqrt[2] Unevaluated[Sqrt[3] + 1] (1 + Sqrt[3]) Unevaluated[Sqrt[2]]. That is correct, but it puzzles me. When I copy and paste this result in an Input cell and evaluate, the result now becomes 2 (1 + Sqrt[3])^2 . That is what I had expected and which is Maxim's result. But when I ask for this result without copying and pasting it does NOT evaluate to 2 (1+Sqrt[3])^2. This is more an evaluation problem (bug?) in version 5.1 than that is has to do with the basic properties of Unevaluated as discussed above. 7. Unevaluated[Sqrt[6]+Sqrt[2]]*Csc[Pi/12]. PreTimes does not apply a rule so we arrive at Times[Sqrt[2], 1 + Sqrt[3], Sqrt[6] + Sqrt[2]] with the last argument labeled. There are no rules for Times to be used, so Mathematica returns Sqrt[2]*(1 + Sqrt[3]) Unevaluated[Sqrt[6] + Sqrt[2]]. Hence, despite the problem mentioned in example 6, my feeling is that there is nothing mysterious and unpredictable in the behaviour of Unevaluated in the examples discussed so far. Fred Simons Eindhoven University of Technology
- Follow-Ups:
- Re: Re: Re: Mathematica language issues
- From: DrBob <drbob@bigfoot.com>
- Re: Re: Re: Mathematica language issues