# How to define a function of non-symbol

Using Displaying index as subscript on output: e.g. C[i] -> C_i with Notation[...] or Interpretation[..]? I have often ended up wanting to define functions of annotated variables to better match my whiteboard mathematics. Naively, I would want to do things like:

f[z[bar]_] := z[bar]^2;
relativez[z_, z[bar]_] := z / z[bar];


However, this doesn't work. Obviously, I can do things like

f[zbar_] := zbar^2;
f[z[bar]]


But I would prefer to have it map to my math better if a simple variation of this pattern works.

• Which is more important: the entry of this function definition, or the way the definition displays with e.g. Definition[f]? Commented Sep 19, 2013 at 19:38
• If it isn't possible to do both at the same time, then I think that current answer gives a possible tradeoff where I can choose as appropriate. Commented Sep 19, 2013 at 20:46

You are close to the truth

f[z_[bar_]] := z[bar]^2;
f[a[b]]

a[b]^2

• So close. Also note that the following works: f2[z_, z_[bar_]] := z/z[bar]; f2[a, a[bar]] Commented Sep 19, 2013 at 17:58
• Just a confirmation though, in your original version the following does not work f[zb], presumably because it needs to match a pattern with a [_]. In this sense, I am not getting exactly what I am want (which is z[bar] as a complete placeholder on its own. However, for my purposes this may be sufficient. Commented Sep 19, 2013 at 18:00

This post contains several code blocks, you can copy them easily with the help of importCode.

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

ClearAll[allowNonSymbol]
SetAttributes[allowNonSymbol, HoldAll]
allowNonSymbol[Set[lhs_, rhs_]] := allowNonSymbol[SetDelayed[lhs, #]] &@rhs
allowNonSymbol[func_SetDelayed] :=
With[{blank = Verbatim[#][___] & /@ (Blank | BlankSequence | BlankNullSequence)},
Module[{newFunc, independentVar}, {newFunc, {independentVar}} =
Reap[Hold@func /.
var_ (holder : blank) :>
RuleCondition[Sow@HoldPattern@var; Pattern[var, holder]] /.
var_ Verbatim[PatternTest][holder : blank, test_] :>

RuleCondition[Sow@HoldPattern@var; PatternTest[Pattern[var, holder], test]] //
Quiet, _, Union[#2] &];
With[{rule = # -> Unique[] & /@ independentVar}, newFunc /. rule // ReleaseHold]]]

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


## Usage

Clear[f, relativez]
mid = z[bar]^2;
allowNonSymbol[f[z[bar] _] = mid];
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 handle BlankSequence[](__) and BlankNullSequence[](___):

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


It can also handle _h and PatternTest:

Clear[f, g]
allowNonSymbol[f[a[2] _Integer] := 2 a[2]]
f[2]
(* 4 *)
f[2.]
(* f[2.] *)
allowNonSymbol[g[a[1] _?NumericQ] := a[1]]
g[3]
Clear[a]; g[a]
(* g[a] *)


## Known issue

1. Patterns like a[1]:{_Integer} can't be used, and it seems to be impossible to overcome the issue, because Mathematica notebook simpliy can't parse the expression:

     a[1] : {_Integer}


1. Patterns like Pattern[a[1], {_Integer}] isn't supported yet.

BTW, it's worth mentioning that non-symbol can be used as independent variables in Compile and ExperimentalCreateNumericalFunction`, see this and this post for more info. (Since these are advanced topics, I'd suggest not to dive into them if you're not experienced enough. )