# Can one shield expressions against replacement?

Posted 3 months ago
783 Views
|
13 Replies
|
5 Total Likes
|
 In an extended expression I would like to shield certain parts of it against replacement. Some identical matching parts would be replaced by a rule applying to the larger expression but certain ones could be shielded and not replaced.
13 Replies
Sort By:
Posted 3 months ago
 David,Can you give an example? How do you want to designate which parts are shielded? Would you put a function around the term? Would it be by position?Regards
Posted 3 months ago
 Neil,I have an Association that has a number of rules that represent points or lines or structures in a geometric diagram, or derivation or proof. The right hand sides are symbolic vector expressions with symbolic basis vectors. I use Strings as Keys because I want to be free to use the Keys in expressions using contextual names and then substitute with the Association to do the calculation. I use Associations because I can gather all the data together for one topic. Here I use just one rule. assoc = Association["A" -> GrassmannPointExpression] There's also a command that will convert the GrassmannPointExpression to a Mathematica List that is applied after the Association. But in the following, which might be used in Graphics, the first "A" is intended to be text and not substituted, and the second "A" will be converted to a position. I would like to shield the first "A" and then un-shield it after the assoc substitution. Text["A", "A"] /. assoc I would like something like the following. HoldAll does not stop replacement. Text[HoldReplacement["A"], "A"] /. assoc // ReleaseHold 
Posted 3 months ago
 David, using Replace instead of ReplaceAll, in combination with Hold, seems to work: assoc=Association["A"->{1,2}] Replace[Text[Hold@"A","A"],assoc,1]//ReleaseHold 
Posted 3 months ago
 Thanks Hans,That doesn't quite work because the expression I'm doing the replacement on is actually an extended List of graphics directives so replacements are needed at various levels. I would like to have just one replace command.I think what I have to do is make certain that none of the Keys in the Association are the same as labels I want in a diagram..
Posted 3 months ago
 Hi David,not that I like my approach very much (it rather looks like a syntactic joke to me), but how about this: With Module[{local}, holdReplacement[s_] := (local = s; "Dummy123"); releaseHoldReplacement := "Dummy123" -> local; ] you can write Text[holdReplacement["A"], "A"] /. assoc /. releaseHoldReplacement (* Out: Text["A",GrassmannPointExpression] *) Is this helpful in any way? Regards -- HenrikEDIT:OK - here comes an "improvement": assoc = Association["A" -> aExpression, "B" -> bExpression, "C" -> cExpression]; Module[{repRules = {}}, holdReplacement[s_] := With[{dummy = Unique[]}, AppendTo[repRules, dummy -> s]; dummy]; releaseHoldReplacement := With[{r = repRules}, repRules = {}; r]; ] then this works: Text[holdReplacement["A"], "A", holdReplacement["B"], "B", holdReplacement["C"], "C"] /. assoc /. releaseHoldReplacement (* Out: Text["A",aExpression,"B",bExpression,"C",cExpression] *) 
Posted 3 months ago
 Hi Henrik,That is a very impressive solution! It appears to work, I was never aware of that particular usage of a Module. Because the routines are defined within a Module they have access to a Module variable like repRules. And the routines can be used outside the Module.Kudos
Posted 3 months ago
 Hi David,glad that you like my approach! I was never aware of that particular usage of a Module Well, this idea of course is not mine, I found it years ago in a contribution made by @Leonid Shifrin (if I remember correctly), so in this respect all credits should go to him! But it is a nice way to give "memory" to a function i.e. mimic static variables.@Neil Singer: I like your solution - and I have the impression that it is more robust. Thanks for sharing! Regards -- Henrik
Posted 3 months ago
 Henrik has a nice solution. Here is an alternative. You can make your own replacement function that will control the order of replacements so you can do what you want. map a function into your expression and replace the new function, f[] depending on the argument. doReplacements[expr_, value_, replacement_] := Module[{f}, Map[f, expr, Infinity] //. f[holdReplacement[f[value]]] -> value //. f[value] -> replacement //. f[arg_] -> arg] Now you can do something like: doReplacements[{holdReplacement["A"], "A", holdReplacement["A"], holdReplacement["B"], "B", holdReplacement["C"], "C"}, "A", "junk"] to get (* {"A", "junk", "A", holdReplacement["B"], "B", holdReplacement["C"], "C"} *) You can expand this concept to handle the association instead of a single replacement. I am not sure if there is any improvement using this approach but it is another way to do this.FYI: holdReplacement cannot be defined -- or you can change it to some other symbolRegards,Neil
Posted 3 months ago
 How about this: assoc = Association["A" -> GrassmannPointExpression]; Text["A", "A"] /. Text[txt_, pos_] :> Text[txt, pos /. assoc] 
Posted 3 months ago
 Gianluca,The problem with that approach is that the Text statements are generally embedded in a larger set of Graphics primitives that will have many substitutions from assoc. So the first argument will still be subject to replacement. Otherwise the assoc replacement would have to be seeded in at many individual places and the whole purpose of simplified transformation with a single use of assoc would be negated.
Posted 3 months ago
 Variation: assoc = Association["A" -> GrassmannPointExpression]; {Point["A"], Text["A", "A"]} /. {Text[txt_, pos_] :> Text[txt, pos /. assoc], "A" -> GrassmannPointExpression} 
 Another approach. This will shield arguments to Hold from replacement attempts, on any level: replaceAllNotHeld[expr_, reprules_] := Module[ {allPos, heldPos, repPos}, allPos = Position[expr, _]; heldPos = Position[expr, Hold] /. 0 -> __; repPos = Intersection @@ (DeleteCases[allPos, #] & /@ heldPos); MapAt[Replace[#, reprules] &, expr, repPos] ] Example: In[2]:= testExpr1 = {Hold@"A", "B", {Hold@"C", "D", Text[Hold@"E", "F"]}} Out[2]= {Hold["A"], "B", {Hold["C"], "D", Text[Hold["E"], "F"]}} In[3]:= replaceAllNotHeld[testExpr1, x_String :> LetterNumber@x] // ReleaseHold Out[3]= {"A", 2, {"C", 4, Text["E", 6]}}