RE: Re: Part assignment
- To: mathgroup at smc.vnet.net
- Subject: [mg45080] RE: [mg45051] Re: Part assignment
- From: "Wolf, Hartmut" <Hartmut.Wolf at t-systems.com>
- Date: Tue, 16 Dec 2003 06:21:06 -0500 (EST)
- Sender: owner-wri-mathgroup at wolfram.com
>-----Original Message----- >From: Maxim [mailto:dontsendhere@.] To: mathgroup at smc.vnet.net >Sent: Sunday, December 14, 2003 12:23 PM >To: mathgroup at smc.vnet.net >Subject: [mg45080] [mg45051] Re: Part assignment > > > > >"Wolf, Hartmut" wrote: > >> >-----Original Message----- >> >From: Maxim [mailto:dontsendhere@.] To: mathgroup at smc.vnet.net >To: mathgroup at smc.vnet.net >> >Sent: Thursday, December 11, 2003 11:28 AM >> >To: mathgroup at smc.vnet.net >> >Subject: [mg45080] [mg45051] Part assignment >> > >> > >> >Consider >> > >> >In[1]:= >> >Module[ >> > {L={0,0}}, >> > L[[1]]=Sequence[1,1]; >> > L[[2]]=2; >> > L[[2]] >> >] >> > >> >Out[1]= >> >1 >> > >> >The first part assignment constructs a list >{Sequence[1,1],0}. Then an >> >interesting thing happens: part extraction functions (Part >and others) >> >think that the second element of this list is 1, while part >assignment >> >(Set) decides that the second element is 0. >> > >> >Maxim Rytin >> >m.r at prontomail.com >> > >> > >> >> Maxim, >> >> obviously you like to live on the edge. Unless you complain, >this is a bold >> way to learn. Observe: >> >> In[32]:= L = {0, 0}; >> L[[1]] = Sequence[1, 1]; >> L[[2]] = 2; >> L[[2]] >> Out[35]= 1 >> >> In[36]:= ?L >> >> Global`L >> >> L = {Sequence[1, 1], 2} >> >> In[48]:= Attributes[Set] >> Out[48]= {HoldFirst, Protected, SequenceHold} >> >> (Look up what SequenceHold means!) >> >> As mostly, you do have alternatives: >> >> In[38]:= L = {0, 0}; >> L = ReplacePart[L, Unevaluated[Sequence[1, 1]], 1]; >> L[[2]] = 2; >> L[[2]] >> >> Out[41]= 2 >> >> In[42]:= ?L >> >> Global`L >> >> L = {1, 2, 0} >> >> -- >> Hartmut Wolf > >So you think SequenceHold is the explanation? Let's see if it >has any relation >to my example. > Well, yes, I thought so, and still do. Proceeding analytically, let's just make a more simple example, a model, which has less complications than the operational semantics of Set. For that I define some "pseudoSet" with an operator that is free for user definition, but has the same grouping properties as Set, I take RightTee: In[16]:= Clear[a, b, c] In[17]:= Attributes[RightTee] = {HoldFirst, SequenceHold}; In[18]:= RightTee[a_, b_, c___] := Print["lhs: ", HoldComplete[a], " \[RightTee] rhs: ", HoldComplete[b], ", " HoldComplete[c]] In[19]:= a \[RightTee] Sequence[b, c] >From In[19]:= lhs: HoldComplete[a] \[RightTee] rhs: HoldComplete[Sequence[b, c]], HoldComplete[] In[20]:= a \[RightTee] b \[RightTee] c >From In[20]:= lhs: HoldComplete[b] \[RightTee] rhs: HoldComplete[c], HoldComplete[] >From In[20]:= lhs: HoldComplete[a] \[RightTee] rhs: HoldComplete[Null], HoldComplete[] This is a consequence of the grouping properties (right associative) the result of the rightmost "assignment" ("value of b" Null) is "assigned to" a In[21]:= Sequence[a, b] \[RightTee] c >From In[21]:= lhs: HoldComplete[Sequence[a, b]] \[RightTee] rhs: HoldComplete[c], HoldComplete[] In[55]:= RightTee[a, b, c] >From In[55]:= lhs: HoldComplete[a] \[RightTee] rhs: HoldComplete[b], HoldComplete[c] Here you see clearly see how slots are filled and SequenceHold is in fact responsible (for the "pseudoassigment" of Sequence[b, c] in FromIn[19]). Now we clear the SequenceHold attribute: In[22]:= ClearAttributes[RightTee, SequenceHold] In[23]:= a \[RightTee] Sequence[b, c] >From In[23]:= lhs: HoldComplete[a] \[RightTee] rhs: HoldComplete[b], HoldComplete[c] In[24]:= Sequence[a, b] \[RightTee] c >From In[24]:= lhs: HoldComplete[a] \[RightTee] rhs: HoldComplete[b], HoldComplete[c] This is the same as the previous result, such also quite different from the corresponding expression with the SequenceHold attribute. (I continue below) >First assignment: L[[1]]=Sequence[1,1], or >Set[Part[L,1],Sequence[1,1]]. >SequenceHold simply determines that it is not converted to >Set[Part[L,1],1,1]. >Curiously enough, in this case it doesn't make any difference, >since the latter >evaluates exactly the same way. > >Second assignment: L[[2]]=2, or Set[Part[L,2],2]. Here L is >not evaluated >(because assigment treats Part in a special way -- if there >were another >non-holding function instead of Part, L would be evaluated), >so there's simply >no Sequence objects here and SequenceHold can't have any effect. > >So references to SequenceHold here are just fancy words -- remove the >SequenceHold attribute of Set and verify that the result will >be exactly the >same. > >The evaluation rules just don't say anything explicitly about >how assignments >should be performed for parts of lists like {Sequence[1,1],0} >(that is, after I >assign a Sequence object to one of the list elements). The >current approach has >its logic too, but it can be misleading, for example, >L[[Length@L]]=elem may >result in an error. > >Maxim Rytin >m.r at prontomail.com > > This of course is not all of Set. Just repeated: In[37]:= Clear[a, b, c] In[38]:= a = Sequence[b, c] Out[38]= Sequence[b, c] In[39]:= ?a Global`a a = Sequence[b, c] In[40]:= ?b Global`b In[41]:= Clear[a, b, c] In[42]:= a = b = c Out[42]= c In[43]:= ?a Global`a a = c In[44]:= ?b Global`b b = c In[45]:= Clear[a, b, c] In[46]:= Sequence[a, b] = c >From In[46]:= Set::write: Tag Sequence in HoldForm[a, b] is Protected. Out[46]= c In[47]:= ?a Global`a Now In[49]:= Clear[a, b, c] In[50]:= Set[a, b, c] Out[50]= Sequence[b, c] This result clearly has nothing to do with SequenceHold, and (as you might see from the "pseudoassignment" this is *not* reached as intermediary from In[38], it just happens to give the same result). Now, anyways, Set is "a proper form" of the language, and certainly lies at the heart of the implementation, and certainly it must be performance optimized. From a programming language perspective, In[50], as contrary to In[38] and In[42], has no semantics. Instead of an error, it shows this behaviour, "is tolerant", but you have to ask the implementor (God himself), why this is so. (My guess is: just to bypass parts from the evaluation loop for Set, hence in reality the were no attributes for Set, as there are no (explicit) UpValues for Part, all this presumably would be "hardwired" at a low level. Perhaps) In[51]:= ?a Global`a a = Sequence[b, c] In[52]:= ?b Global`b Let's look again at your first question: >> In[32]:= L = {0, 0}; >> L[[1]] = Sequence[1, 1]; >> L[[2]] = 2; >> L[[2]] >> Out[35]= 1 >> >> In[36]:= ?L >> >> Global`L >> >> L = {Sequence[1, 1], 2} We certainly agree that after the second assignment L[[1]]= Sequence[1,1] has the value {Sequence[1,1], 0}, (it would have the same value after the assignment Set[L[[1]],1,1], but that is, as shown, a different story). Now why does L[[2]] = 2, overwrite that 0, and not the second 1 from Sequence[1,1]? This simply is because of the HoldFirst property of Set (such L ist *not* evaluated, does *not* result to {1, 1, 0}[[2]] at lhs, and as a special form behaves "like an Upvalue for Part" just redefining the second slot, and leaving everthing else untouched (of course, we might say), hence the result. Contrary to that, L = L evaluates L at rhs to {1, 1, 0}, this then is assigned to the symbol L completely overwriting its previous value. Thereafter L[[2]]=2 of course results in {1, 2, 0} Whereas in L[[2]], when evaluated, L first results in {1,1,2}, and {1,1,2}[[2]] then in turn gives 1 (and not 2). You may detect more (seemingly) strange behaviour for Set, as (if e.g. matrix A is properly set up) A[[1, 1]] = something gives a correct assignment, whereas A[[1]][[1]] = something doesn't. This also is due to HoldFirst and the "UpValue" behaviour for Part. All this, after you respect the Attributes (you always have to), and consider the needs for an efficient implementation, is not very surprising. Perhaps we may regret that WRI is a bit reserved on these and similar questions, but this should not become a problem of usage. My advice was, and is: avoid that! (because, as said, it's outside of the programming language specification and semantics). -- Hartmut Wolf