Skip to main content

functions - Enforcing correct variable bindings and avoiding renamings for conflicting variables in nested scoping constructs


Using global variables the following turns an "expression" into a Function:


expr = 2 x;
Function[x, Evaluate[expr]]


Of course this doesn't work if for some reason a value is assigned to x. Thus, I want to turn expr into a Function inside a Module. But it seems like there is a scoping problem:


Module[{x, expr},
expr = 2 x;
Function[x, Evaluate[expr]]
]

(* Function[x$, 2 x$1713] *)

Clearly, the x used in the first argument of Function is not the same as the x in the second. I played around with Evaluate and even with Replace and Slot, also trying to create a function with an anonymous variable, but didn't succeed. The only way that I managed to get the right result is this one involving strings:


Module[{x, expr},

expr = 2 x;
"(" <> StringReplace[ToString@expr, ToString@x -> "#1"] <> ")&" // ToExpression
]

Is there a simpler, more straight-forward way to achieve this, without ever using any global variables?



Answer



Scoping constructs, lexical scoping and variable renamings


It pays off to understand a bit deeper how the scoping constructs work and what happens behind the scenes when you execute one. In addition to the documentation, this was discussed in part here, but let us present some summary.


When the lexical scoping construct Sc[vars, body] executes (where Sc can stand for constructs such as With,Module, Function), evaluation roughly happens via the following steps (or at least this represents our current understanding of it):




  • First, the list of local variables vars is analyzed.

  • The body is analyzed, and the presence of inner scoping constructs is tested. This test is performed verbatim, so that, to be detected, some inner scoping construct ScInner has to be present in body in the form ScInner[innerVars, innerBody]. If the inner scoping construct is dynamically generated at run-time (via ScInner @@ ... or otherwise), it is not detected by Sc during this stage.

  • If some inner scoping constructs are found where some variables conflict with vars, then Sc renames them. It is important to stress that it is Sc that does these renamings in the inner scoping constructs. Indeed, those are inert during that stage (since Sc has HoldAll attribute and so body is kept unevaluated), so Sc is the only function in a position to do those renamings.

  • The actual variable binding happens. The body is searched for instances of vars, and those instances are lexically bound to the variables.

  • Depending on the nature of the scoping construct, further actions may be performed. Function does nothing, With performs the replacements of symbols (variables) with their values in body (according to bindings), while Module creates var$xxx variables (according to the bindings, both in the initialization and body), and then performs variables initializations.

  • The code in body is actually allowed to evaluate.


How to fool scoping constructs


From the above description, it is clear that, if one wants to avoid renamings for some inner lexical scoping construct ScInner[innerVars, innerBody] for whatever reason, one has to dynamically generated this code, so that it is not present inside Sc verbatim. Again, depending on the situation, one may or may not want to evaluate innerVars and innerBody.


More often than not one wants to prevent such evaluation, so it is typical to use something like



With[{y = boundToZ}, With @@ Hold[{y = z}, boundToZ]] 

or


With[{y = boundToZ}, Hold[{y = z}, boundToZ] /. Hold -> With]

or anything else that would prevent the innerVars or innerBody from unwanted early evaluation.


Here is a more meaningful example. The following is a new scoping construct, which executes some code code with a variable var bind to a current value extracted from a Java iterator object:


ClearAll[javaIterate];
SetAttributes[javaIterate, HoldAll];
javaIterate[var_Symbol, code_][iteratorInstance_?JavaObjectQ] :=

While[iteratorInstance@hasNext[],
With @@ Hold[{var = iteratorInstance@next[]}, code]
];

The iteratorInstance is expected to be a Mathematica reference for Java object implementing Iterator interface. The variable var is bound to the current value of the iterator (extracted via iteratorInstance@next[]), using With. This is non-trivial, since we construct this With from pieces, and therefore generate lexical binding of this var to the occurrences of var in code, at every iteration of the While loop. In this case, the outer protecting scoping construct is actually SetDelayed. And we need the construct With @@ Hold[...] to prevent variable var renaming, which is exactly what we don't want here.




However, there are cases, where we do want some or all of innerVars or innerBody to evaluate before the binding stage for the inner scoping constructs. The case at hand falls into this category. In such a case, perhaps the most straight-forward way is to use Sc @@ {innerVars, innerBody}, which is what acl did in his answer.


The case at hand


It is now clear why this solution works:


Module[{x, expr},

expr = 2 x;
Function @@ {x, expr}
]


Function[x$5494, 2 x$5494]

Since there wasn't a line Function[x,...] present verbatim, Module did not detect it. And since we do want the variable and body to evaluate before Function performs the variable bindings, the second version (Function @@ {...}) has been used.


You will note that Evaluate is not needed because List is does not have the HoldAll attribute. This specific syntax is not the only approach. For example h[x, expr] /. h -> Function or ReplacePart[{x, expr}, 0 -> Function] would also work because there is not an explicit Function[x, . . .] in the code.


It is instructive to realize that this version works too:



Module[{x, expr}, 
expr = 2 x;
Function[Evaluate[x], Evaluate[expr]]
]

while Function[...] is present here, the presence of extra Evaluate around x in Function made it impossible for Module to detect the conflict. Of course, there are many other ways one can achieve the same effect.


It is now also clear why the following will not work:


Module[{x, expr},
expr = 2 x;
Function[x, z] /. z -> expr

]


Function[x, 2 x$151]

The point is, the substitution z -> expr happens only at the stage when the body of the Module is evaluated, while the binding stage happens earlier (as described above). During the binding stage, Module detects the name conflict all right, and of course renames. Only then is x converted into a newly created x$151, and only after all that the code inside Module executes - by which time it is too late since the symbols inside Function and expr are different.


The case of Block


Block is a natural approach when guarding against global values, but as Szabolcs comments it must be used with care. Block is not seen a scoping construct for the purposes of the automatic renaming described in the tutorial. You can also see some additional relevant discussion here. Because of that you will not get the "protection" that you may be accustomed to. Using Szabolcs's example:


f[z_] := Block[{x, expr}, expr = 2 x + z; Function[x, Evaluate[expr]]]


f[x]


Function[x, 3 x]

Note that this function will triple its argument rather than doubling and adding Global`x which may or may not be what you were expecting. Such injection is often very useful but at the same time if you are accustomed to the automatic renaming behavior (even if you are unaware of the mechanism) this may come as a surprise.


Comments

Popular posts from this blog

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...