Почему Mathematica нарушает нормальные правила определения объема в модуле? - PullRequest
7 голосов
/ 29 апреля 2010

Как указывалось в недавней публикации , область действия не работает должным образом внутри модуля.

Пример из этой темы:

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

Но следующее работает почти так, как ожидалось.

Module[{expr},
 expr = 2 z;
  Set@@{f[z_], expr};
  f[7]]
(*14*)

На каком языке дизайн учитывал Вольфрам, выбирая эту функциональность?

Edit: см. Первый комментарий Jefromi. Я изменил z с локальной переменной на not и забыл изменить вывод. Это не влияет на проблему.

Edit2: Похоже, Майкл Пилат считает, что Блок и Модуль имеют разные функции. Я думаю, что понимаю его точку зрения, но я думаю, что это ортогонально моему вопросу. Итак, вот обновление.

Я могу использовать следующий код на глобальном уровне в записной книжке:

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

Но когда я помещаю один и тот же блок кода в модуль и делаю expr локальным, это приводит к другому выводу.

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

Если вы проследите приведенный выше вызов модуля, вы обнаружите, что Set [f [z_], expr] переписан в Set [f [z $ _, expr]. Теперь это преобразование z-> z $ происходит как по lhs, так и по rhs множества. Однако это происходит до того, как expr будет оценен, что приведет к тому, что на глобальном уровне будет получен другой результат.

Преобразование z-> z $, по-видимому, происходит только тогда, когда у rhs есть локальный для вызова модуля символ.

Почему Mathematica выбирает изменение синтаксиса при вызове модуля? Какие языковые / конструктивные компромиссы существуют здесь, которые приняли это решение.

Ответы [ 2 ]

5 голосов
/ 30 апреля 2010

Я думаю, что ответ довольно простой, но тонкий: Module - это лексическая ограничивающая конструкция, а Block - это динамическая ограничивающая конструкция.

В блоке по сравнению с модулями в документации рассматривается различие:

Когда используется лексическая область видимости, переменные обрабатываются как локальные для определенного раздела кода в программе. В динамической области видимости значения переменных являются локальными для части истории выполнения программы. В скомпилированных языках, таких как C и Java, существует очень четкое различие между «кодом» и «историей выполнения». Символическая природа Mathematica делает это различие несколько менее ясным, поскольку в принципе «код» может быть создан динамически во время выполнения программы.

Что делает Module[vars, body], так это обрабатывает форму тела выражения в то время, когда модуль выполняется как «код» программы Mathematica. Затем, когда любая из переменных явно появляется в этом «коде», она считается локальной. Block[vars, body] не смотрит на форму тела выражения. Вместо этого во время оценки тела блок использует локальные значения для переменных.

Предлагает этот сокращенный пример:

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

Возможно, ключевым моментом является осознание того, что Module заменяет все экземпляры i в теле модуля локализованной версией (например, i$1234) лексически , до любое тело модуля фактически оценивается.

Таким образом, тело модуля, которое фактически оценивается, равно i$1234 + m, затем i$1234 + i^2, затем a + i^2.

Ничего не сломано, Block и Module должны вести себя по-разному.

2 голосов
/ 30 апреля 2010

Согласно документации , Module имеет атрибут HoldAll, который заставляет все внутри Module оставаться в неоцененном состоянии, поэтому ваш expr не оценивается как 2 z до присвоения expr f[z_].

Перенос второго аргумента в Module в Evaluate, кажется, решает проблему:

In[1]:= Module[{expr}, Evaluate[expr = 2 z;
  f[z_] = expr;
  f[7]]]

Out[1]= 14

Также, использование Block вместо Module работает:

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

Out[2]= 14
...