Лексическая и динамическая область видимости в Mathematica: локальные переменные с модулем, с и блоком
следующий код возвращает 14, как и следовало ожидать:
Block[{expr},
expr = 2 z;
f[z_] = expr;
f[7]]
но если вы измените, что Block
до Module
затем он возвращает 2*z
.
Кажется, не имеет значения, какие другие переменные, кроме expr
локализации.
Я думал, что понял модуль, блок и С в Mathematica, но я не могу объяснить разницу в поведении между модулем и блоком в этом примере.
связанные ресурсы:
- учебник по модульности и именованию Вещи!--14--> из документации Mathematica
- отрывок из книги книга Пола Р. Веллина, Ричарда Дж. Гейлорда и Сэмюэла Н. камина
- объяснение от Дэйва Withoff в группе новостей Mathematica
PS: спасибо Майкл Пилат, Davorak и Билл Уайт на след-след на этой странности. Даворак уточняет и добирается до проблема здесь: почему Mathematica нарушает нормальные правила области видимости в модуле?
3 ответов
я тоже был немного удивлен этим, но я не думаю, что это ошибка. Если вы посмотрите глубоко в примерах ссылка на страницу для Module
под заголовком Возможные Проблемы, есть небольшая записка, которая говорит "переменные переименовываются во вложенные области" и приводит следующий пример:
In[1]:= Module[{e = Expand[(1 + x)^5]}, Function[x, e]]
Out[1]= Function[x$, e94]
In[2]:= %[10]
Out[2]= 1 + 5 x + 10 x^2 + 10 x^3 + 5 x^4 + x^5
Function
еще один обзорный построить как Module
, Так что x
переименовано внутри x$
в рамках Function
, подобно тому, что вы обнаружили с Trace
о z
.
в своем Module
определение f
, Set
- еще одна такая масштабирующая конструкция, и поэтому z
переименован, когда f
определена в Module
, но не тогда, когда он внутри Block
. Следуя совету этого примера из Module
документация, вы можете построить RHS вашей функции из ее частей, чтобы избежать лексического переименования вложенного область применения:
In[3]:= Clear[f, z]
In[4]:= Module[{expr},
expr = 2 z;
Set @@ {f[z_], expr};
f[7]]
Out[4]= 14
HTH!
во-первых, я думаю, что вы обнаружили ошибку здесь.
во-вторых, я думаю, что могу предложить некоторое понимание того, почему это происходит, имея в виду, что мои знания о внутренних частях mathematica ограничены.
такое утверждение, как: f[z_]: = 2 z в полной форме:
SetDelayed[f[Pattern[z, Blank[]]], 2 z]
это устанавливает DownValue[f] в:
{HoldPattern[f[z_]] :> 2 z}
затем позже, когда выражение, такое как f[2], позже оценивается, что-то вроде следующего заготовлено:
f[2] /. HoldPattern[f[z_]] :> 2 z
который будет оценивать до 4. Теперь это все возможно, потому что сопоставление шаблонов происходит с шаблоном[z, Blank[]] из первого блока кода. Это работает, даже если вы извращенно установили z в число. Иначе говоря.
z = 5;
f[z_] := 2*z
по-прежнему производит те же значения downvalues для f:
{HoldPattern[f[z_]] :> 2 z}
это возможно, потому что Pattern имеет атрибут HoldFirst.
атрибут HoldFirst не является достаточной защитой, если вы оцените это внутри модуля. Пример:
SetAttributes[tmp, HoldFirst];
Module[{expr},
expr = 2 z;
tmp[expr]
]
выходы:
tmp[expr29]
Я предлагаю, поскольку атрибут HoldFirst не обеспечивает иммунитета к правилу перезаписи переменных модуля, что любой шаблон в правиле, содержащем локальную переменную, перезаписывает свои переменные шаблона. sym - > символ[Имя_символа[sym]~~"$"]
Module[{expr},
Hold[z_ -> (z; expr)]
]
(*Hold[z$_ -> (z$; expr91)]*)
z был переписан с обеих сторон правила в простом Альфа-преобразовании.
Если правило не содержит местных переменная не переписывается:
Module[{expr},
Hold[z_ -> (z)]
]
(*Hold[z_ -> z]*)
вместо того, чтобы искать, соответствует ли локальная переменная переменной правила, применяется вышеупомянутое общее правило.
таким образом, проблема заключается в том, что локальный expr не оценивается до Альфа-преобразования происходит. Или, возможно, еще лучше было бы иметь expr, завернутый в лениво оцененное Альфа-преобразование, которое потребуется для RuleDelayed.
этого не происходит в блоке, потому что блок не переписывает локальных переменных.
есть другие идеи? Кто-нибудь видит дыры в моей логике?