How to scope `Pattern` labels in rules/set?
While Set
isn't a scoping construct (SC), it is considered one by other SCs outer to it. ref / Set / Details[[-3]] (thanks to Alexey Popkov for correcting me).
Here it is inner to the Module
and Module
decides not to interfere in this case (don't know why), but you can trick it:
Module[{x},
Set @@ {f[x_], Integrate[y^2, {y, 0, x}]};
]
?f
f[x$301_]=x$301^3/3
Further reading: Enforcing correct variable bindings and avoiding renamings for conflicting variables in nested scoping constructs
This issue has been discussed before in
- I define a variable as local to a module BUT then the module uses its global value! Why?
Regarding your motivation a solution of mine, which you linked to yourself, is shown in
- How to make a function like Set, but with a Block construct for the pattern names
What is left is to implement a Module
alternative as you attempted, or to use some alternative to Rule
, Set
, etc., as shown in other answers. I shall explore making a Module
alternative more robust. To pick apart your starting code:
Unique@x
will evaluatex
; this is unacceptable.The local Symbol lacks the
Temporary
attribute and will not be garbage-collected.Only a single local Symbol may be specified.
There is no provision for assignments within the first parameter.
Here is my attempt to fix these limitations.
SetAttributes[module, HoldAll]
clean = Replace[#, (Set | SetDelayed)[s_Symbol, _] :> s, {2}] &;
module[{sets : (_Symbol | _Set | _SetDelayed) ..}, body_] :=
(List @@ #;
Unevaluated[body] /.
List @@ MapAt[HoldPattern, {All, 1}] @
Thread[clean[Hold[sets] :> #], Hold]) & @ Module[{sets}, Hold[sets]]
Now:
x = 1;
module[{x},
f @ x_ = x;
p @ x_ := x;
{x, x_, x_ -> x, x_ :> x}
]
?f
?p
{x$533, x$533_, x$533_ -> x$533, x$533_ :> x$533} f[x$533_]=x$533 p[x$533_]:=x$533
And also:
module[{x, y = 3, z := Print["foo!"]},
{x, y, x_, y_, x_ -> x y, x_ :> x, z_ :> x y}
]
{x$533, 3, x$533_, y$533_, x$533_ -> 3 x$533, x$533_ :> x$533, z$533_ :> x$533 y$533}
I think a third kind of behaviour would also be possible: it is debatable whether f@x_ = x, x_ -> x
within Module[{x}, ...
should not become f@x_ = x$123, x_ -> x$123
because then the sequence
ClearAll[Global`x];
x = 1;
0 /. x_ -> x
would do the same whether executed in the global context or within a Module[{x}, ...]
. It currently does not: With a fresh kernel (or after clearing x
), the program gives 1 in the global context and 0
within a Module[{x}, ...]
:
ClearAll[Global`x];
Module[{x}, x = 1; 0 /. x_ -> x]
Use Hold, Unique, ReleaseHold
as you demonstrated if you want some specific renaming to happen within pattern labels of Set, SetDelayed, Rule, RuleDelayed
- Module
will not descend into these by design.