The Problem
Consider the following code (1):
In[1]:= x = 2;
Module[{x, y},
y[x_] = x;
y[1]
]
Out[2]= 2
I expected the answer to be 1 since I assumed that x would be replaced with a local variable. The code returns the expected result if I replace Module with Block. However, I do not see why x would be out of scope of a lexical scoping construct. The effect can be demonstrated in a more drastic way with the following code (2):
In[3]:= x = 2;
Module[{x, y},
y[x_] = (x = 1);
];
x
Out[5]= 1
The x inside the Module is not replaced with a local version and the value of the variable on the outside of the module is changed instead.
My own attempt (Can be skipped)
to trace the problem:
In[6]:= x = 2;
Module[{x, y},
y[x_] = x;
y[1]
] // Trace
Out[7]= {Module[{x,y},y[x_]=x;y[1]],{y$2016[x_]=x;y$2016[1],{{x,2},y$2016[x_]=2,2},{y$2016[1],2},2},2}
This shows that the only y is replaced with a local version.
Next I had a look at the Code (3) that the Kernel sees:
In[8]:= x = 2;
Module[{x, y},
y[x_] = x;
y[1]
] // Hold // FullForm
Out[9]//FullForm= Hold[Module[List[x,y],CompoundExpression[Set[y[Pattern[x,Blank[]]],x],y[1]]]]
and contrasted it with the code (4):
In[10]:= x = 2;
Module[{x, y},
y = x;
y[1]
] // Hold // FullForm
Out[11]//FullForm= Hold[Module[List[x,y],CompoundExpression[Set[y,x],y[1]]]]
From a lexical point of view the difference between code (3) and (4) is only y[Pattern[x,Blank[]]]
vs y
. However in (3) x is not a local variable and in (4) it is.
Since Module has the Attribute HoldAll, I expect it to treat its Body in a purely lexical way before any of the attributes of the expression inside the body or whatnot apply.
I am aware that Set has the attributes HoldFirst and SequenceHold, but I do not see why this would make a difference in this case since Module localizes the variables even for held expressions.
Does the Kernel see x as a Symbol?:
In[12]:= Clear[x];
Hold[
Module[{x, y},
y[x_] = x;
y[1]
]] // Cases[#, _Symbol, Infinity] &
Out[12]= {x,y,x,x}
This suggests to me that the x on the left and right hand side of the Set is a Symbol and that it should be replaced with a localized version.
Resources considered (Can be skipped)
Since the code is so simple I highly expect this question to be either a lack of my understanding or a duplicate. However unfortunately I could neither find the answer
- in the documentation of Module
- nor in What are the use cases for different scoping constructs?
nor in the various other questions I checked. A local function inside a Module is not uncommon, however, the combination of Set with a pattern on the left as a localized variable inside a Module seems quite specific. I did not encounter it elsewhere.
The Question
Please explain the result of code (1).
Thanks in advance for answers or helpful pointers.