Проблемы совместимости
Мы уже не раз обращали внимание на то, что при создании документов нередки конфликты между переменными, назначаемыми пользователем, и переменными, входящими в программы ядра, между функциями пользователя и встроенными функциями, между их заголовками и т. д. Ситуация усложняется при использовании пакетов расширения, поскольку в них широко используются переменные и различные функции, причем нередко обозначенные так же, как и встроенные функции.
Особенно коварны побочные эффекты в конструкциях, содержащих вспомогательные переменные, – например, в итерационных циклах, функциях вычисления суммы и произведения и т. п. Они содержат переменные-итераторы i, .j, k и т. д. Обычно избежать конфликтов можно с помощью механизма локализации итераторов. Вернемся к уже обсуждавшимся примерам. Возьмем пример с вычислением суммы:
i
=
2
2
Sum[i, {i,
1
,
4
}]
10
i
2
Ясно, что сумма вычисляется с применением цикла с заданным числом повторений. В его конце итератор i получает значение 4. Но глобальная переменная с тем же именем имеет значение 1=2, которое она получила до вычисления суммы с помощью функции Sum. В данном случае это достигнуто за счет того, что в теле функции переменная-итератор является локальной.
Нетрудно убедиться, что проблемы со статусом переменных возможны и в, казалось бы, изученных функциях суммирования и перемножения. На это явно указывает следующий пример:
func[x_] :
=
Sum[x
^
i, {i,
4
} ] {func[y], func[i]}
(y
+
y2
+
y3
+
y4,
30
}
i
2
Результат вычисления func [у] вполне понятен, тогда как вычисление func [i] носит явно обескураживающий характер. Причина его в том, что вместо символьного значения i в данном случае оказались использованы численные значения итератора i. А в этом случае функция Sum просто вычисляет численные значения. Говорят, что она работает по контексту.
А теперь рассмотрим пример с циклом For:
For[i
=
1
, i
<
=
4
, i
+
+
, Print[i]]
1
2
3
4
i
5
На этот раз переменная i изменила свое значение в конце цикла с 2 на 5. Это говорит о том, что пользователю-программисту надо очень внимательно относиться к статусу переменных во всех итерационных, да и других программах.
Разумеется, Mathematica содержит средства для избежания подобного смешения ролей переменных. Одно из них – применение конструкции Module:
i
=
2
2
Module[{i},For[i
=
1
, i
<
=
4
, i
+
+
, Print[i]]]
1
2
3
4
i
2
На этот раз захвата итератором глобальной переменной i удалось избежать. Однако этот пример носит не более чем частный характер. Вообще говоря, если переменная-итератор задается в теле функции, то она будет локальной, а если она задается за пределами функций, то глобальной.