В C я использовал добавление слова static рядом с переменной, когда определяю локальную переменную внутри функции, если я хотел, чтобы значение локальной переменной сохранялось между вызовами.
Это дало мне локальную защиту области видимости имени переменной, но в то же время значение переменной было постоянным.Было очень полезно эмулировать простой объект, который сохраняет свое личное состояние.
http://en.wikipedia.org/wiki/Local_variable#Static_local_variables
Возможно ли эмулировать это в Mathematica, используя Module[]
?или DynamicModule[]
?
(мы знаем, Module[]
не сохраняет состояние локальных переменных по умолчанию, но как насчет использования DynamicModule[]
?)
Нет использования пакетов.Контекст использования этого находится внутри Manipulate[]
.
Нет Module[]
может быть вне Manipulate.Следовательно, все должно быть примерно так:
Manipulate[
foo[]:=Module[{a,b,c},....];
boo[]:=Module[{a,b,c},....];
... foo[] ..
... boo[]...
..,
control_variables...,
Initialization:>
(
.... global area....
)
]
Я пытался использовать DynamicModule
вместо Module[]
выше, но DynamicModules
не может быть вызвано как функция?и я не мог понять, как это сделать.
вопрос в том, можно ли заставить функцию запоминать значение ее локальных переменных между вызовами, как, например, можно использовать C с локальными статическими переменными?
конечно, нельзя сохранить состояние в глобальных переменных, и в этом весь смысл моего вопроса.Я хотел бы, чтобы состояние модуля сохранялось в контексте, который принадлежит только этому модулю.
Я не прошу какой-либо дополнительной эмуляции OO.Просто хотел сохранить несколько локальных переменных, используемых модулем, в области имен, которые принадлежат этому модулю, а не в глобальном контексте, и обеспечить их постоянство между вызовами модуля.
Обновление
Для ясности, вот очень простой пример C
#include <stdio.h>
void my_add(void)
{
static int total = 0;
total = total + 1;
printf("current total %d\n",total);
}
int main()
{
int i;
for(i = 1; i<=3; i++)
my_add();
return 0;
}
$ gcc ex.c
$ ./a.exe
current total 1
current total 2
current total 3
$
Обновление 8:45
Это для решения WReach.Вот что я попробовал:
Manipulate[
n;
Module[{total = 0},
processA[] :=
(
total = total + 1
)
];
Module[{total = 0},
processB[] :=
(
total = total + 1
)
];
Grid[{
{"module A total=", processA[]},
{"module B total=", processB[]}
}],
Button["press to update state", n++],
{{n, 0}, None},
TrackedSymbols :> {n}
]
Общая сумма остается 1 каждый раз, когда я нажимаю кнопку.Не сохраняется последнее значение.
Обновление 9:13
Для решения WReach внутри Manipulate:
Вот тест:
Manipulate[
n;
Grid[{
{"module A result=", aResult}
}],
Button["press to update process A", {n++; aResult = processA[n]}],
{{n, 0}, None},
{{aResult, {}}, None},
TrackedSymbols :> {n},
Initialization :>
(
Module[{total = 0},
processA[n_] :=
(
total = total + 1;
{n, total}
)
]
)
]
Сам по себе, похоже, работает.Но когда я сделал копию ячейки, и вставил ее в новую ячейку.Затем запустите второй Манипулятор, чтобы обновить итоговое значение, затем вернитесь к первому Манипулятору, чтобы обновить итоговое значение, и я вижу, что он использует обновленный итог второго Манипулятора.Следовательно, это глобально.
Это не разрешено в демо.Снимки сделаны, и они не могут совместно использовать состояние (в демо не допускаются глобальные переменные. Раздел инициализации не должен содержать глобальных общих данных. Но может содержать функции, которые вызываются через параметры только из выражения Manipulate, нет проблем).
обновление 9:40 *
Ответ на второй пример мистера Волшебника, приведенный ниже, для примера, который он показал:
Manipulate[
{x, myAdd[]},
{x, 1, 10},
{{total, 0}, None},
{{myAdd, (total += 1; total) &}, None}
]
Проблема в том, что имя total
не может использоваться двумя различными функциями. Пространство имен для total
находится во всем Manipulate. Что я хотел бы, используя этот шаблон, примерно так:
Manipulate[
ctrl;
Grid[{
{"processA result=", processA[]},
{"processB result=", processB[]}
}],
Button["step", ctrl++],
{{ctrl, 0}, None},
{{processA, Module[{total = 0}, total++] &}, None},
{{processB, Module[{total = 0}, total++] &}, None},
TrackedSymbols :> {ctrl}
]
Вы видите, что выше, у processA есть свой локальный итог, а также processB. То же самое локальное имя. Вышеприведенное не работает. Если я заменим вышеприведенное на следующее, чтобы сделать этоwork '
Manipulate[
ctrl;
Grid[{
{"processA result=", processA[]},
{"processB result=", processB[]}
}],
Button["step", ctrl++],
{{ctrl, 0}, None},
{{total, 0}, None},
{{processA, Module[{}, total++] &}, None},
{{processB, Module[{}, total++] &}, None},
TrackedSymbols :> {ctrl}
]
Тогда processA и processB теперь совместно используют одну и ту же переменную итогового значения. Это сводит на нет весь смысл наличия каждого в отдельном пространстве имен, но при этом сохраняетсяВ течение срока службы вызовов.
Обновление 10:00
Оппс, у меня был плохой способ написания этого модуля [] в приведенном выше примере.Вот почему это не работает.Пожалуйста, игнорируйте мое обновление 9:40 утра.Я исправляю это сейчас, и обновлю через несколько минут.Это может на самом деле работать.
обновление 10:08
Хорошо, вот совок: в 9:40 утра, когда я сказал «вышеописанное не работает», это потому, что у меня была неправильная установка, неправильное место (). Я исправил это. Сейчас я показываю решение, на которое ссылается WReach, под заголовком Избегание глобальных определений
Новость заключается в том, что он работает для ОДНОЙ манипуляции. Когда я копирую манипуляцию в другую ячейку, счетчики распределяются между двумя манипуляциями.
Вот пример: (исправленная версия того, что было у меня в 9:40 утра)
Manipulate[
ctrl;
Print["in top of Manipulate"];
Grid[{
{"processA current total=", aResult},
{"processA current total=", bResult}
}],
Button["update A process", {ctrl++; aResult = processA[]}],
Button["update B process", {ctrl++; bResult = processB[]}],
{{ctrl, 0}, None},
{{aResult, 0}, None},
{{bResult, 0}, None},
{{processA, Module[{total = 0}, ( total = total + 1; total) &]},
None},
{{processB, Module[{total = 0}, (total = total + 1; total) &]}, None},
TrackedSymbols :> {ctrl}
]
Установка работает, пока есть одна копия Манипулята. Как только я копирую Манипулировать сам в новую ячейку, и изменяю это, первое обновляется. счетчики глобальные:
Так что, жаль, эти решения не работают для меня. Попробую позже функцию контекста вещь. Но сначала нужно узнать больше об этом.
обновление 12:00
Чтобы проиллюстрировать, что я делаю сейчас, в ответ на приведенный ниже MrWizard, для каждого имеющегося у меня «решателя» я предварительно фиксирую имя каждого из его параметров с помощью pn
, где n
- это идентификационный номер решателя. Итак, у меня есть p1StepNumber, p2StepNumber, p3StepNumber, p1Solution, p2Solution, p3Solution и т. Д. *
Затем, когда я хочу вызвать solver 1, я передаю ему параметры p1 * и при возврате возвращает обратно решение и любые обновления, которые будут сохранены в области Manipulate Control-> None для последующего вызова, и так далее.
Следовательно, состояние каждого решателя сохраняется / сохраняется внутри Манипуляции как переменная Control-> None. Поскольку Manipulate - это DynamicModule, они сохраняются между вызовами, и даже когда я закрываю M и снова открываю его.
Вот снимок экрана с частичным списком моих параметров Манипулятора в области Control-None, для иллюстрации. все это и многое другое в одном манипуляторе. Когда пользователь меняет решатель, весь пользовательский интерфейс также изменяется с новым макетом, специфичным для этого решателя.
Благодаря использованию метода Leonid Macro, я теперь могу легко это сделать:).
Было бы лучше, если бы я мог сохранять эти «внутри» каждого решателя, и чтобы каждый решатель был отдельным модулем, где каждый решатель будет сохранять свое собственное состояние, а Manipulate будет просто передавать ему параметр пользовательского интерфейса каждый раз, когда это необходимо. обновите, а все остальное будет сохранено внутри решателя (ей), к которому они принадлежат.
Отсутствие даже структуры для управления этим означает, что каждый мой вызов содержит более 20-30 параметров. Так как мне нужно каждый раз передавать решателю все его состояние и возвращать его вместе с возвратами. Это не так уж и плохо, я просто должен привыкнуть делать вызовы с 30 параметрами каждый раз, что я не использую. Но я пока не вижу другого чистого пути. Вот почему я задал этот вопрос.
обновление 24.12.11 18:00
Это ниже ответ на предложение Szabolcs и telefunkenvf14 использовать имя контекста функции.
Я пришел к выводу, что этот метод тоже не работает. Та же проблема, что и у других методов.
Как только я делаю копию самого Манипулятора, переменные становятся общими для двух копий Манипулятора.
Ниже приведен пример, показывающий проблему:
Remove["Global`*"]
Manipulate[
ctrl;
Print["in top of Manipulate"];
Grid[{
{"processA current total=", aResult},
{"processA current total=", bResult}
}],
Button["update A process", {ctrl++; aResult = processA[]}],
Button["update B process", {ctrl++; bResult = processB[]}],
{{ctrl, 0}, None},
{{aResult, 0}, None},
{{bResult, 0}, None},
{{processA, Module[{},
(
If[! ValueQ[processA`total], processA`total = 0];
processA`total = processA`total + 1;
processA`total
) &]}, None},
{{processB, Module[{},
(
If[! ValueQ[processB`total], processB`total = 0];
processB`total = processB`total + 1;
processB`total
) &]}, None},
TrackedSymbols :> {ctrl}
]
Теперь я скопировал вышеупомянутое в новую ячейку и нажал на кнопки, и я вижу, что счетчики теперь опережают значения в предыдущей копии Manipulate. Таким образом, процесс`A является общим. Это локально для каждой конкретной функции.
Точно такая же проблема с другим опробованным методом, поэтому этот метод у меня не работает.