[Date Index] [Thread Index] [Author Index]
I was thinking at how to measure the Length of an expression in the form that is entered by the user. The way to do it is: Length[Unevaluated[expr]] For example Length[Unevaluated[2+5]] gives 2 which is what I wanted since 2+5 is really Plus[2,5], a function with 2 arguments. So far so good. Then I started to experiment a bit with Unevaluated and I soon discovered that it behaves curiously . To peek at the inner workings of Mathematica I always like to switch On and then try remembering to switch Off again very quickly, before doing something silly. So look at this: Type: On Unevaluated[2+5]//Length Off and you get (line numbering added for clarity) On::trace: On --> Null. >> Length::trace: Length[Unevaluated[2+5]] --> Length[2+5]. >> (* Line 1 *) Length::trace: Length[2+5] --> 2. >> (* Line 2 *) Out= 2 Which is what we got before. Now let's see what happens if we split the oneliner expression Unevaluated[2+5]//Length in 2 parts. Normally this should have no consequences, but in this case... On Unevaluated[2+5] %//Length Off On::trace: On --> Null. >> Out= Unevaluated[2+5] Out::trace: % --> Out[$Line-1]. >> $Line::trace: $Line --> 281. >> Plus::trace: $Line-1 --> 281-1. >> Plus::trace: 281-1 --> 280. >> Out::trace: Out[$Line-1] --> %280. >> Out::trace: %280 --> Unevaluated[2+5]. >> Length::trace: Length[%] --> Length[Unevaluated[2+5]]. >> Length::trace: Length[Unevaluated[2+5]] --> 1. >> (* Line 3 *) Out= 1 It gives a different result! This is vaguely hinted at in the Unevaluated info page under Properties & Relations "Unevaluated works only where it appears; it is not propagated" This probably means that it is not wise to split things up when dealing with Unevaluated. Yet, how does Mathematica know? Compare line 1 with line 3 : both start with the same Length[Unevaluated[2+5]], yet the result is different! I find this a bit amazing. Obviously something is going on behind the scenes that is not revealed with a simple On. Look now at Line 2. Isn't that amazing? A simple looking Length[2+5] is evaluated as 2. It should be either 0, because Length is 0 or it should be 1, if we imagine some invisible wrapper (HoldForm?, Unevaluated?) protecting 2+5. Length has no special attributes, yet 2+5 is taken as Plus[2,5] and its length evaluates to 2. However all of this is totally invisible. Just for comparison type In:= On Length[2+5] Off On::trace: On --> Null. >> Plus::trace: 2+5 --> 7. >> Length::trace: Length[2+5] --> Length. >> (* Line 4 *) Length::trace: Length --> 0. >> Out= 0 Compare line 2 above with Line 4 here, they start the same, yet they end up very differently. All this suggests to me that either Unevaluated has a very odd and unique non-standard evaluation or that it has some undocumented side effects at least at a local (ie. temporary) level. Any comments?