Следующий код возвращается 14, как Вы ожидали бы:
Block[{expr},
expr = 2 z;
f[z_] = expr;
f[7]]
Но если Вы изменяете это Block
к a Module
затем это возвращается 2*z
. Это, кажется, не имеет значение что другие переменные, кроме того, expr
Вы локализуете. Я думал, что понял Модуль, Блок, и С в Mathematica, но я не могу объяснить различие в поведении между Модулем и Блоком в этом примере.
Связанные ресурсы:
PS: Благодаря Michael Pilat, Davorak и Bill White для следующего след аромата на этой странности. Davorak разъясняется и добирается до сути проблемы здесь: Почему Mathematica повредил бы нормальные правила обзора данных в Модуле?
Я тоже был немного удивлен этим, но не думаю, что это ошибка. Если вы внимательно посмотрите примеры на справочной странице для Module
, в разделе, помеченном Возможные проблемы , есть небольшая заметка, в которой говорится «Переменные переименованы в вложенные области " и дает следующий пример:
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
Функция
- это еще одна конструкция области видимости, такая как Модуль
, поэтому x
внутренне переименовывается в x $
в области действия функции
, аналогично тому, что вы обнаружили с помощью Trace
о z
.
В вашем модуле
, определяющем f
, Set
является другой такой конструкцией области видимости, и поэтому z
переименовывается, когда f
определяется внутри модуля
, но не внутри блока
.Следуя совету этого примера из документации Module
, вы можете построить правую часть вашей функции из ее частей, чтобы избежать лексического переименования вложенной области видимости:
In[3]:= Clear[f, z]
In[4]:= Module[{expr},
expr = 2 z;
Set @@ {f[z_], expr};
f[7]]
Out[4]= 14
HTH!
Во-первых, я думаю, вы обнаружили здесь ошибку.
Во-вторых, я думаю, что могу предложить некоторое понимание того, почему это происходит, имея в виду, что мои знания о внутреннем устройстве математики ограничены.
Заявление наподобие: 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. Теперь это все возможно, потому что сопоставление с образцом происходит с Pattern [z, Blank []] из первого блока кода. Это работает, даже если вы ранее установили z на число. Другими словами.
z = 5;
f[z_] := 2*z
По-прежнему производит те же понижающие значения для f:
{HoldPattern[f[z_]] :> 2 z}
Это возможно, потому что Pattern имеет атрибут HoldFirst.
Атрибут HoldFirst не является достаточной защитой, если вы оцениваете это внутри модуля. Пример:
SetAttributes[tmp, HoldFirst];
Module[{expr},
expr = 2 z;
tmp[expr]
]
output:
tmp[expr$8129]
Я предлагаю это, поскольку атрибут HoldFirst не обеспечивает невосприимчивость к правилу перезаписи переменной модуля, что любое В шаблоне в правиле, содержащем локальную переменную, были перезаписаны переменные шаблона.sym-> Symbol [SymbolName [sym] ~~ "$"]
Module[{expr},
Hold[z_ -> (z; expr)]
]
(*Hold[z$_ -> (z$; expr$1391)]*)
z был переписан с обеих сторон правила путем простого альфа-преобразования.
Если правило не содержит локальной переменной, перезапись не происходит:
Module[{expr},
Hold[z_ -> (z)]
]
(*Hold[z_ -> z]*)
Вместо поиска, чтобы увидеть, соответствует ли локальная переменная переменной правила, применяется вышеуказанное общее правило.
Проблема в том, что локальное выражение не оценивается до того, как произойдет альфа-преобразование. Или, возможно, еще лучше было бы обернуть expr в лениво оцениваемое альфа-преобразование, которое потребовалось бы для RuleDelayed.
Этого не происходит в блоке, поскольку блок не перезаписывает никакие локальные переменные.
Есть еще идеи? Кто-нибудь видит какие-нибудь дыры в моей логике?