Re: string-variable-Set-snarl
- To: mathgroup at smc.vnet.net
- Subject: [mg22498] Re: [mg22491] string-variable-Set-snarl
- From: Hartmut Wolf <hwolf at debis.com>
- Date: Wed, 8 Mar 2000 02:22:39 -0500 (EST)
- Organization: debis Systemhaus
- References: <200003050524.AAA14078@smc.vnet.net>
- Sender: owner-wri-mathgroup at wolfram.com
Dear James, and all of the community, yesterday I answered to your posting James Fuite and Tania Nordli schrieben: > > Dear Advanced Mathematica Users, > > The following is a short and perhaps trivial problem that has caused me > some frustration. I cannot write a program that allows me to change the > value of any given variable if given the name of the variable as a > string. What follows is an equivalent situation. Let > > In[3]= {cow = Random[], emu = Random[], ant = Random[]} > Out[3]= {0.2, 0.3, 0.4} > > . . . . some selection process . . . . > > In[25]= animalname > Out[25]= cow > > In[25]= Head[animalname] > Out[25]= String > > Given a string, here "cow", corresponding to a variable, here cow, I > cannot clear or set a value for the variable itself. Of course I cannot > use Clear[cow] or cow = 2 because I do not know which variable will be > chosen, as represented by the variable animalname. My lame attempts > such as Clear[animalname] or ToExpression[animalname] = 2 only fail to > affect cow - it seems that I am caught trying to work on the wrong side > of the equals sign (Set)! My goal would be a line such as: > > In[28]= ToExpression[animalname] > Out[28]= 2 > > which I think would imply that cow = 2 and has thus been affected. Who > can guide me from line 25 to line 28? What are the general > considerations? > > Sincerely, > James J. Fuite. ...yet my answer is either overly complex, or flawed somewhat. I will not quote it here, instead give some explanation of my reasoning -- and a new, better solution -- and not avoid being somewhat lengthy. But I think what I found out deserves it, since it is of fundamental importance. The base problem behind your quest is: "how do I get at the *unevaluated* symbol, given it's name?" If the symbol has no value, Symbol[<symbol name>] will do, but if the symbol already has got a value, whenever you wan't to evaluate Symbol[<symbol name>] to get at the symbol itself, evaluation will proceed further, which excludes its use at the lhs of Set. It's only Wolfram Inc. who could prevent that. A rude solution to this problem would be to Clear the symbol beforehand -- since it is going to be reset: In[1]:= Attributes[setsymbol] = {HoldAll}; In[2]:= setsymbol[s_String, rhs_] := (Clear[s]; Evaluate[Symbol[s]] = Unevaluated[rhs]) In[3]:= setsymbol[s_Symbol, rhs_] := Unevaluated[s] = Unevaluated[rhs] Then... In[4]:= setsymbol["cow", 11]; In[5]:= cow Out[5]= 11 ... of course works, but you can't do In[6]:= setsymbol["cow", cow + 1] $RecursionLimit::"reclim": "Recursion depth of \!\(256\) exceeded." Out[6]= 254 + Hold[cow + 1] In[7]:= cow $RecursionLimit::"reclim": "Recursion depth of \!\(256\) exceeded." Out[7]= 255 + Hold[cow + 1] To avoid this you may give setsymbol only the HoldFirst attribute: In[1]:= Attributes[setsymbol] = {HoldFirst}; In[2]:= setsymbol[s_String, rhs_] := (Clear[s]; Evaluate[Symbol[s]] = rhs) In[3]:= setsymbol[s_Symbol, rhs_] := Unevaluated[s] = rhs ...and then In[4]:= setsymbol["cow", 11]; In[5]:= cow Out[5]= 11 In[6]:= setsymbol["cow", cow + 1]; In[7]:= cow Out[7]= 12 But now we have destroyed the semantics of Set, i.e. the rhs must always be evaluated (or if you wrap with enough layers of Unevaluated, you'll get back the problem above). It was my goal to keep the exact semantics of Set. The idea was to register the variables of the problem at hand *unevaluated* such that mysymbol[<symbol name>] :> Unevaluated[symbol]. If you know all your variables (or variable names for that matter) in advance before your calculation, then you may register them and go on. But perhaps this might become arkward; so my idea was to register the variables at their first use (with setsymbol). The program published yesterday does that, yet there remains a problem when the variable has been (perhaps inadvertendly) used before. So I got caught back by the initial ploblem I wanted to avoid. I lost my nerves and introduced that Clear -- though only at their first "legal" use. But this morning I found out a much better way! Here it is: In[1]:= mysymbol[s_String] := Symbol[s] In[2]:= mysymbol[s_Symbol] := Unevaluated at Unevaluated[s] In[3]:= Attributes[setsymbol] = {HoldAll}; In[4]:= setsymbol[s_, rhs_] := ((#1 = #2) &)[mysymbol[Unevaluated[s]], Unevaluated[rhs]] In[5]:= $NewSymbol = (With[{s = Symbol[#1]}, mysymbol[#1] = Unevaluated at Unevaluated[s]] &); Let me give a short discussion: If a variable is given as a symbol, then mysymbol just returns that symbol unevaluated, and that unevaluated symbol is inserted at the lhs of Set, whereas the rhs also is inserted unevaluated. Further progress is now identical to s = rhs. If a variable is given as a string, it's name, then if it's registered mysymbol[<variable name>] retrieves the unevaluated symbol, that is inserted at the lhs of Set, ok. If the variable has not been registered before, and if it was not existent, then the symbol is generated with Symbol[<symbol name>] (which cannot evaluate further) and is inserted at the lhs of Set. This works as long as there are no unregistered variables. Here now $NewSymbol comes in. This system symbol is a hook for a function that intercepts the process of generating a new symbol. We use it to register any variable in status nascendi! With is used there as to get the evaluated Symbol[<symbol name>], i.e. the new symbol itself into the rhs of the definition. Unevaluated appears twice since evaluation of this expression (Set) removes one Unevaluated and the second one is left in the definition, that one we need so urgent! Kind regards, Hartmut
- References:
- string-variable-Set-snarl
- From: James Fuite and Tania Nordli <jfuite@UAlberta.ca>
- string-variable-Set-snarl