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:

  1. Unique@x will evaluate x; this is unacceptable.

  2. The local Symbol lacks the Temporary attribute and will not be garbage-collected.

  3. Only a single local Symbol may be specified.

  4. 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.