I have many delayed-defined functions of many variables, and all the functions share a term containing some of these variables. Thus, I would like to just call the term x and for each function to immediately read x as that term. What would be the easiest/best/cleanest way to do this?

As a very simplified example, the code

x = a1 + a2;
f[a1_, a2_, a3_] := x + a3
f[b1, b2, b3]

gives the output

a1 + a2 + b3

but the output I want is

b1 + b2 + b3

Given my problem, the following concerns and conditions are understandable.

  • I want to avoid defining x explicitly as a function (i.e. x[...]) because it depends on many variables, it would be called many times, and x[...] would end up being almost as large as the term it is supposed to be a shortcut for.

  • I want to avoid calling Module[] or Block[] or using replacement rules in each function because I would have to do this for many functions and they are complicated enough as it is. This is why I would like the definition for x to be global.

It seems like there should be a straightforward way for Mathematica to just immediately read a symbol x in each delayed-defined function as a term containing some of the functions' arguments.

  • 1
    $\begingroup$ Can you just use f[a1_, a2_, a3_] = x + a3? $\endgroup$ – Carl Woll Oct 25 '18 at 16:17
  • $\begingroup$ I am using delayed-defined functions. $\endgroup$ – Just Some Old Man Oct 25 '18 at 16:20
  • $\begingroup$ Would something like globalEnvironment[x->a1+a2, f[a1_,a2_, a3_] = x+a3, g[a1_, a2_, a3_] = x^2-a3, ...] work, or do you want to modify how SetDelayed works (i.e., modify a built-in symbol) so that you can just use f[a1_,a2_, a3_] = x+a3; g[a1_, a2_, a3_] = x^2-a3? $\endgroup$ – Carl Woll Oct 25 '18 at 16:50
  • $\begingroup$ @Carl I would like something like the effects of globalEnvironment, except I wouldn't want to define a large number of big functions inside one function. I don't need to modify SetDelayed overall, except maybe for how it works just the symbol x. $\endgroup$ – Just Some Old Man Oct 25 '18 at 20:09
  • 1
    $\begingroup$ Despite your aversion to Block I believe it is the correct solution here. I consider this question a duplicate of (69590), which I answered with blockSet; please try that before rejecting the idea. $\endgroup$ – Mr.Wizard Oct 27 '18 at 17:55

This does not avoid defining x as a function, but I believe it meets the required usage nonetheless, and involves no shenanigans with scoping constructs or replacement rules

xpattern = PatternSequence[a1_, a2_];
xfunc[xpattern] = a1 + a2;
f[x : xpattern, a3_] := xfunc[x] + a3

Now we have

f[b1, b2, b3]
(* b1 + b2 + b3 *)

How about modifying $Pre?:

$Pre = Function[expr, 
   Unevaluated[expr] /. a__SetDelayed :> (Unevaluated@a /. OwnValues@x), HoldAll];

x = a1 + a2;
f[a1_, a2_, a3_] := x + a3;
g[a1_, a2_, a3_] := x a3
DownValues /@ {f, g}

(* {{HoldPattern[f[a1_, a2_, a3_]] :> (a1 + a2) + a3}, 
    {HoldPattern[g[a1_, a2_, a3_]] :> (a1 + a2) a3}} *)

Here is another idea. Create an UpValues for x so that using TagSetDelayed with the tag x does what you want:

TagSetDelayed[x, lhs_, rhs_]  ^:= SetDelayed @@ (Hold[lhs, rhs] /. OwnValues[x])

For your example:

x = a1 + a2;
x /: f[a1_, a2_, a3_] := x + a3



{HoldPattern[f[a1_, a2_, a3_]] :> (a1 + a2) + a3}

  • $\begingroup$ @Mr.Wizard You need to use x /: f[a1_, a2_, a3_] := 1/x + a3, that's the whole point of the TagSetDelayed definition. $\endgroup$ – Carl Woll Oct 27 '18 at 18:04
  • $\begingroup$ @Mr.Wizard What does ?x return? $\endgroup$ – Carl Woll Oct 27 '18 at 18:15
  • $\begingroup$ Well nuts, it's working now (in a new session, two hours later) so I guess I had a lingering definition messing things up. Noob mistake! Sorry, and belated +1. ( And to answer your question I get x=a1+a2 (x/:lhs_:=rhs_)^:=SetDelayed@@(Hold[lhs,rhs]/. OwnValues[x]) ) $\endgroup$ – Mr.Wizard Oct 27 '18 at 21:03

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