Lexical and dynamic scaling in Mathematica: local variables with module, with and block

The following code returns 14 as you expected:

Block[{expr}, expr = 2 z; f[z_] = expr; f[7]] 

But if you change this Block to Module , then it will return 2*z . It doesn't seem to matter what other variables besides expr you localize. I thought I understood Module, Block and With in Mathematica, but I cannot explain the difference in behavior between the module and the block in this example.

Related Resources:

PS: Thanks to Michael Pilate , Davorak and Bill White for following this oddity. Daworak clarifies and gets to the core of the problem: Why does Mathematica break the normal rules for determining the scope in a module?

+7
variables scope module wolfram-mathematica localization
source share
3 answers

I was also a little surprised by this, but I do not think this is a mistake. If you look in the examples on the page for Module , under Possible Problems there is a small note that says: "Variables are renamed in nested areas" and gives the following example:

 In[1]:= Module[{e = Expand[(1 + x)^5]}, Function[x, e]] Out[1]= Function[x$, e$1194] In[2]:= %[10] Out[2]= 1 + 5 x + 10 x^2 + 10 x^3 + 5 x^4 + x^5 

Function is another area of ​​definition, such as Module , so x renamed internally inside x$ to the Function area, similar to what you found with Trace near z .

In Module f Set Set is another such scope scheme, and therefore z renamed when f is defined inside the Module , but not when inside the Block . Following the recommendations of this example from the Module documentation, you can create the RHS of your function from its parts to avoid lexical renaming of the nested area:

 In[3]:= Clear[f, z] In[4]:= Module[{expr}, expr = 2 z; Set @@ {f[z_], expr}; f[7]] Out[4]= 14 

NTN!

+6
source share

First of all, I think you found a mistake here.

Secondly, I think I can offer some insight into why this happens, bearing in mind that my knowledge of mathematics is limited.

Type operator: f [z_]: = 2 z in full form:

 SetDelayed[f[Pattern[z, Blank[]]], 2 z] 

This sets the value of DownValue [f]:

 {HoldPattern[f[z_]] :> 2 z} 

Then later, when an expression like f [2] is later evaluated, the following is true:

 f[2] /. HoldPattern[f[z_]] :> 2 z 

That will be evaluated to 4. Now all this is possible, because pattern matching occurs with the template [z, Blank []] from the first code block. This works even if you firmly set z to a number. In other words.

 z = 5; f[z_] := 2*z 

Still produces the same down for f:

 {HoldPattern[f[z_]] :> 2 z} 

This is possible because the template has a HoldFirst attribute.

The HoldFirst attribute is not sufficiently protected if you evaluate it inside a module. Example:

 SetAttributes[tmp, HoldFirst]; Module[{expr}, expr = 2 z; tmp[expr] ] 

outputs:

 tmp[expr$8129] 

I suggest, because the HoldFirst attribute does not provide immunity to the rule for rewriting a module variable, that any template in a rule that contains a local variable overwrites template variables. sim-> Symbol [SymbolName [SYM] ~~ "$"]

 Module[{expr}, Hold[z_ -> (z; expr)] ] (*Hold[z$_ -> (z$; expr$1391)]*) 

z was rewritten on both sides of the rule in a simple alpha transform.

If the rule does not contain a local variable, rewriting is not performed:

 Module[{expr}, Hold[z_ -> (z)] ] (*Hold[z_ -> z]*) 

Instead of looking to see if the local variable matches the rule variable, the above rule applies.

So the problem is that the local expr is not evaluated before alpha conversion occurs. Or maybe it would be even better to have expr wrapped in the lazily evaluated alpha transform that RuleDelayed would need.

This does not happen in the block, because Block does not overwrite any of the local variables.

Any other ideas? Does anyone see any holes in my logic?

+3
source share

Do you use Trace for both expressions?

+2
source share

All Articles