views:

232

answers:

2

As was pointed out in a recent post scoping does not work as expected inside of Module.

An example from that thread is:

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 consideration made wolfram choose this functionality?

Edit: See Jefromi's first comment I changed z from being a local variable to not and forgot to change the output. It does not effect the problem.

Edit2: Michael Pilat's point seems to be that Block and Module have different functions. I think I understand his point, but I think that it is orthogonal to my question. So here is an update.

I can use the following code at the the global level in a notebook:

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

But when I put the same code block into a Module and make expr local it produces a different output.

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

If you trace the above Module call you find that Set[f[z_], expr] is rewritten to Set[f[z$_,expr]. Now this z->z$ transformation happens on both the lhs and rhs of the Set. It however happens before expr is evaluated, which causes a different result then would be obtained at the global level.

The transformation z->z$ only seems to happen when the rhs has a symbol local to the Module call.

Why does Mathematica choose to have this syntax change in a Module call? What language/implementation design tradeoffs exist here that made this decision.

+1  A: 

According to the documentation, Module has attribute HoldAll, which causes everything inside the Module to remain in an unevaluated state, so your expr is not evaluated to 2 z before expr is assigned to f[z_].

Wrapping 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

Also, using Block instead of Module works:

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

Out[2]= 14
Isaac
By using Evaluate though you have made expr a global variable instead of a local one.
Davorak
+4  A: 

I think the answer is pretty simple, but subtle: Module is a lexical scoping construct, and Block is a dynamic scoping construct.

The Blocks Compared With Modules tutorial from the documentation discusses the distinction:

When lexical scoping is used, variables are treated as local to a particular section of the code in a program. In dynamic scoping, the values of variables are local to a part of the execution history of the program. In compiled languages like C and Java, there is a very clear distinction between "code" and "execution history". The symbolic nature of Mathematica makes this distinction slightly less clear, since "code" can in principle be built up dynamically during the execution of a program.

What Module[vars, body] does is to treat the form of the expression body at the time when the module is executed as the "code" of a Mathematica program. Then when any of the vars explicitly appears in this "code", it is considered to be local. Block[vars, body] does not look at the form of the expression body. Instead, throughout the evaluation of body, the block uses local values for the vars.

It offers this reduced 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 to realize that Module replaces all instances of i in the module body with a localized version (e.g., i$1234) lexically, before any of the body of the module is actually evaluated.

Thus, the module body that's actually evaluated is i$1234 + m, then i$1234 + i^2, then a + i^2.

Nothing is broken, Block and Module are intended to behave differently.

Michael Pilat
That is close to what I answered in the last question. The point of lexically scoping something is so that you can make some variables local and leaves everything else unchanged. Module does not leave everything else unchanged. How does changing the available syntax serve Module's purpose? Look at the Trace of the Modules above one with f[z_]=expr and one with f[z_] = <anything but a local variable >. The former has z rewritten as z$ and in the later z stays unchanged. Why does Module interact with additional internal scoping this way? Is there some language design criteria that I am missing?
Davorak
If Module did not rewrite z as z$ in the later case then the Set of f[z_] would have worked as it would have out side of a module statement and how would expect it to work. Also thank you.
Davorak
Just in case it was not clear I do not understand how you example is supposed to apply to the example I provided since all of the Sets in my example happen in the Module statement and yours does not.
Davorak
Thank you for your thought out response. I updated my question with some clarifications, please let me know if this makes my question clear.
Davorak
Sorry, I haven't let this go, I've been both busy and trying to research a solid answer for you. Hope to update my answer soon =)
Michael Pilat
Thank you I appreciate it, looking forward to the update.
Davorak