Лексический и динамический обзор в Mathematica: Локальные переменные с Модулем, С, и Блок

Следующий код возвращается 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 повредил бы нормальные правила обзора данных в Модуле?

7
задан Community 23 May 2017 в 12:19
поделиться

3 ответа

Я тоже был немного удивлен этим, но не думаю, что это ошибка. Если вы внимательно посмотрите примеры на справочной странице для 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!

6
ответ дан 6 December 2019 в 23:02
поделиться

Вы использовали трассировку для обоих выражений?

2
ответ дан 6 December 2019 в 23:02
поделиться

Во-первых, я думаю, вы обнаружили здесь ошибку.

Во-вторых, я думаю, что могу предложить некоторое понимание того, почему это происходит, имея в виду, что мои знания о внутреннем устройстве математики ограничены.

Заявление наподобие: 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.

Этого не происходит в блоке, поскольку блок не перезаписывает никакие локальные переменные.

Есть еще идеи? Кто-нибудь видит какие-нибудь дыры в моей логике?

3
ответ дан 6 December 2019 в 23:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: