Skip to main content
2 of 9
bug fixed
xzczd
  • 68.4k
  • 9
  • 174
  • 489

The following is an attempt for making a general purpose function for this task:

ClearAll[allowNonSymbol]
SetAttributes[allowNonSymbol, HoldAll]
allowNonSymbol[func : (h : Set | SetDelayed)[lhs_, rhs_]] := 
 With[{blank = Verbatim /@ (Blank[] | BlankSequence[] | BlankNullSequence[])}, 
  With[{independentVar = Union@Cases[Unevaluated@lhs, var_ blank :> var, Infinity]}, 
   With[{rule = # -> Unique[] & /@ independentVar}, 
    Hold[func] /. (var : Alternatives @@ independentVar) (holder : blank) :> 
         Pattern[var, holder] /. rule // ReleaseHold // Quiet]]]

allowNonSymbol[func : Function[independentVar_, rhs__]] := 
 With[{rule = # -> Unique[] & /@ Flatten@{independentVar}}, 
  Hold[func] /. rule // ReleaseHold]

Usage:

Clear[f, relativez]
allowNonSymbol[f[z[bar] _] := z[bar]^2];
allowNonSymbol[relativez[z_, z[bar] _] := z/z[bar]];
f[3]
(* 9 *)
relativez[2, 3]
(* 2/3 *)

allowNonSymbol can be used on pure function:

sin = allowNonSymbol@Function[b[1], Sin@b[1]];
Sin[2.]
(* 0.909297 *)

It can also handle BlankSequence[](__) and BlankNullSequence[](___):

allowNonSymbol[times[argu[n] __] := Times[argu[n]]]
times[2, 3, 5]
(* 30 *)
allowNonSymbol[join[lst_, ele[i] ___] := Join[lst, ele[i]]]
join[{3}]
(* {3} *)

But it'll fail on more complicated cases, for example:

(* The following won't work: *)
Clear[f, g]
allowNonSymbol[f[a[2] _Integer] := 2 a[2]]
f[2]
allowNonSymbol[g[a[1] _?NumericQ] := a[1]]
g[3]

Well, as mentioned at beginning, this is just an attempt. Hope someone more knowledgable will come up with a more general solution.

xzczd
  • 68.4k
  • 9
  • 174
  • 489