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;

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

  • $\begingroup$ Which is more important: the entry of this function definition, or the way the definition displays with e.g. Definition[f]? $\endgroup$
    – Mr.Wizard
    Sep 19, 2013 at 19:38
  • $\begingroup$ 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. $\endgroup$
    – jlperla
    Sep 19, 2013 at 20:46

2 Answers 2


You are close to the truth

f[z_[bar_]] := z[bar]^2;
  • $\begingroup$ So close. Also note that the following works: f2[z_, z_[bar_]] := z/z[bar]; f2[a, a[bar]] $\endgroup$
    – jlperla
    Sep 19, 2013 at 17:58
  • 1
    $\begingroup$ 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. $\endgroup$
    – jlperla
    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:

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]


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

allowNonSymbol can be used on pure function:

sin = allowNonSymbol@Function[b[1], Sin@b[1]];
(* 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]]]
(* {3} *)

It can also handle _h and PatternTest:

Clear[f, g]
allowNonSymbol[f[a[2] _Integer] := 2 a[2]]
(* 4 *)
(* f[2.] *)
allowNonSymbol[g[a[1] _?NumericQ] := a[1]]
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}

enter image description here

  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 Experimental`CreateNumericalFunction, 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. )


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.