Why does Mathematica break the normal scope rules in a module?

As indicated in a recent post, the scope within the module does not work.

An example from this thread:

Module[{expr}, expr = 2 z; f[z_] = expr; f[7]] (*2 z*) 

But the following works almost as expected.

 Module[{expr}, expr = 2 z; Set@@{f[z_], expr}; f[7]] (*14*) 

What language design made tungsten choose this functionality?

Edit: see Jefromi's first comment. I changed z to a local variable and did not forget to change the output. This does not affect the problem.

Edit2: It seems that Michael Pilate's position is that the block and module have different functions. I think I understand his point of view, but I think that is orthogonal to my question. So here is the update.

I can use the following code globally in a laptop:

 expr = 2 z; f[z_] = expr; f[7] (*output: 14*) 

But when I put the same block of code in the module and do expr local, it produces a different output.

 Clear[f]; Module[{expr}, expr = 2 z; f[z_] = expr; f[7]] (*output: 2z*) 

If you follow the above module call, you will find that Set [f [z_], expr] is rewritten to Set [f [z $ _, expr]. Now this transformation z-> z $ occurs on both lhs and rhs Set. However, this happens before expr is evaluated, which leads to another result being obtained globally.

The z-> z $ conversion seems to happen only when rhs has a character local to the module call.

Why did Mathematica decide to change this syntax in a module call? What trade-offs between language and project implementation exist here that made this decision.

+7
programming-languages wolfram-mathematica
source share
2 answers

I think the answer is quite simple, but subtle: Module is the lexical domain of definition, and Block is the dynamic domain of definition.

Blocks compared to modules in the textbook from the documentation discuss the differences:

When lexical coverage is used, variables are considered local for a specific section of code in the program. With dynamic scaling, the values โ€‹โ€‹of variables are local to part of the program execution history. In compiled languages โ€‹โ€‹such as C and Java, there is a very clear distinction between โ€œcodeโ€ and โ€œexecution historyโ€. The symbolic nature of Mathematica makes this distinction a little less clear, since the "code" can, in principle, be dynamically generated at runtime.

What Module[vars, body] does is related to the form of the body of the expression when the module is executed as the "code" of the Mathematica program. Then, when any of the vars clearly appears in this "code", it is considered local. Block[vars, body] does not look at the body shape of an expression. Instead, in the whole body evaluation, the block uses local values โ€‹โ€‹for vars.

He offers this given example:

 In[1]:= m = i^2 Out[1]= i^2 (* The local value for i in the block is used throughout the evaluation of i+m. *) In[2]:= Block[{i = a}, i + m] Out[2]= a + a^2 (* Here only the i that appears explicitly in i+m is treated as a local variable. *) In[3]:= Module[{i = a}, i + m] Out[3]= a + i^2 

Perhaps the key point is the realization that Module replaces all instances of i in the module body with a localized version (for example, i$1234 ) lexically, before any module body is actually evaluated.

Thus, the body of the module that is actually priced is i$1234 + m , then i$1234 + i^2 , then a + i^2 .

Nothing is broken, Block and Module should behave differently.

+5
source share

According to the documentation , Module has a HoldAll attribute, which means that everything inside the Module remains in an invaluable state, so your expr not evaluated to 2 z before expr assigned f[z_] .

Bypassing the second argument to Module in Evaluate seems to solve the problem:

 In[1]:= Module[{expr}, Evaluate[expr = 2 z; f[z_] = expr; f[7]]] Out[1]= 14 

In addition, using Block instead of Module works:

 In[2]:= Block[{expr = 2 z}, f[z_] = expr; f[7]] Out[2]= 14 
+2
source share

All Articles