4

For example I have some global assignments x=1;y=2;z=3 and an expression Hold[x*y/z]. How can I now extract variables {x,y,z} from this expression, do some manipulations with them and substitute their values back?

The point is to be able to this without providing variable names by hand inside of Block like so:

Block[{x,y,z},
  ..
]
swish
  • 7,881
  • 26
  • 48

2 Answers2

6

Here is one way (I seem to remember that something similar was discussed before, but could not find it):

ClearAll[withBlockedVars];
SetAttributes[withBlockedVars,HoldRest];
withBlockedVars[Hold[expr_],code_]:=
    With[
    {
        heldVars=
            Thread[                    
                Cases[                        
                    Unevaluated[expr],
                    s_Symbol/;Context[s]==="Global`"&&DownValues[s]==={}:>
                        HoldComplete[s],
                    \[Infinity],
                    Heads->True
                ],
                HoldComplete
            ]
    },
        heldVars/. 
            HoldComplete[vars_List]:>Block[vars,code]
    ]

which tries to dynamically determine which symbols to block (it has some arbitrariness in the criteria). Here is how you can use this:

x = 1; y = 2; z = 3;
withBlockedVars[
  Hold[x*y/z], 
  Hold[x*y/z] /. {x -> y + z, y -> x + z, z -> x + y}
]

(*  Hold[((y + z) (x + z))/(x + y)] *)
Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
1

I'm not certain if I'm understanding your request correctly, but if you are looking simply to make replacements using the symbols that appear in the expression, you can make do with using HoldPattern. So using Leonids example, you would use:

Hold[x*y/z] /. { HoldPattern[x] :> y + z^x, 
                 HoldPattern[y] :> x + z, 
                 HoldPattern[z] :> x + y}
(* Hold[((y + z^x) (x + z))/(x + y)] *)

Since it's a delayed rule the inserted expressions aren't evaluated, and HoldPattern prevents the left hands of the rules from evaluating.

jVincent
  • 14,766
  • 1
  • 42
  • 74