Mathematica 中有什么简单的机制可以使模块具有持久状态吗?
在 C 中,如果我希望在调用之间保存局部变量值,当我在函数内定义局部变量时,我常常在变量旁边添加“static”一词。
这给了我变量名的局部范围保护,但同时变量值是持久的。对于模拟保存其私有状态的简单对象非常有用。
http://en.wikipedia.org/wiki/Local_variable#Static_local_variables
可能吗使用 Module[]
在 Mathematica 中模拟这一点?或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 语言和局部静态变量可以做到这一点?
当然,无法保存状态在全局变量中,这就是我问这个问题的全部意义。我希望将模块状态保存在仅属于该模块的上下文中。
我并不要求任何高级的面向对象模拟。只是想将模块使用的一些局部变量保存在属于该模块的名称范围中,而不是保存在全局上下文中,并让它们在模块调用之间保持不变。
更新
需要明确的是,这是一个非常基本的 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 AM
这是针对 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 更新
对于 Manipulate 中的 WReach 解决方案:
这是一个测试:
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,更新那里的总数,然后返回第一个 Manipulate 更新那里的总数,我看到它正在使用第二个 Manipulate 更新的总数。因此它是全球性的。
这在演示中是不允许的。拍摄快照,并且它们不能共享状态(演示中不允许使用全局变量。初始化部分不得包含全局共享数据。但可以包含仅从 Manipulate 表达式通过参数调用的函数,没问题
更新9:40 AM
回复Mr Wizard 下面的第二个例子,他展示的模式如下:
Manipulate[
{x, myAdd[]},
{x, 1, 10},
{{total, 0}, None},
{{myAdd, (total += 1; total) &}, None}
]
这个问题是,名称total
可以。不能被 2 个不同的函数使用。 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 也是如此。相同的本地名称。如果我用以下内容替换上面的内容以使其“工作”,
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 点更新
Opps,我在上面的示例中编写 Module[] 的方法很糟糕 这就是它不起作用的原因。请忽略我上午 9:40 的更新。我现在正在纠正它,并将在几分钟内更新。它可能真的有效。
更新10:08 AM
好吧,这是独家新闻:在我上午9:40,当我说“以上不起作用”时,是因为我的设置错误,()的位置错误。我纠正了这一点。我现在展示了 WReach 在避免全局定义标题下提到的解决方案。
消息是它适用于 ONE 操作。一旦我将操作复制到另一个单元格,计数器就会在两个操作之间共享。
这是一个示例:(我在上午 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}
]
设置只要有一份 Manipulate 副本,就可以工作。一旦我将 Manipulate 本身复制到新单元格并对其进行修改,第一个单元格就会更新。计数器是全局的:
所以,太糟糕了,这些解决方案对我不起作用。稍后会尝试函数上下文的事情。但首先需要对其进行更多了解。
更新 12 PM
为了说明我现在所做的,在下面回复 MrWizard 时,对于我拥有的每个“求解器”,我通过 pn
,其中 n
是求解器 ID 号。所以我有 p1StepNumber、p2StepNumber、p3StepNumber、p1Solution、p2Solution、p3Solution 等...
然后当我想调用求解器 1 时,我将 p1* 参数传递给它,并在返回时返回解和任何更新以保存在Manipulate Control->None区域中供以后调用,依此类推。
因此,每个解算器的状态在 Manipulate 内部保留/保存为 Control->None 变量。由于 Manipulate 是 DynamicModule,因此它们会在调用之间保存,甚至当我关闭 M 并重新打开它时也是如此。
下面是 Control-None 区域中 Manipulate 参数的部分列表的屏幕截图,以进行说明。所有这些以及更多内容都在一个 Manipulate 中。当用户更改解算器时,整个 UI 也会发生变化,并使用特定于该解算器的新布局。
感谢 Leonid Macro 方法的使用,我现在能够轻松地做到这一点:)。
如果我可以将这些保存在每个解算器“内部”,并且让每个解算器成为一个单独的模块,其中每个解算器将保存自己的状态,并且 Manipulate 每次需要刷新时都会将 UI 参数传递给它,那么效果会更好其他所有内容都保存在它们所属的解算器中。
甚至没有一个结构来管理它,这意味着我所做的每个调用都有超过 20-30 个参数。因为我每次都需要向求解器传递其所有状态,并通过返回将其取回。还不错,我只是要习惯每次调用 30 个参数,这是我不习惯的。但到目前为止我还没有看到其他干净的方法。这就是我问这个问题的原因。
更新时间:2011 年 12 月 24 日下午 6 点 以下是对 Szabolcs 和 telefunkenvf14 使用函数上下文名称的建议的回应。
我发现的结论是这个方法也行不通。与其他方法相同的问题。
一旦我制作了 Manipulate 本身的副本,变量就会在 Manipulate 的 2 个副本之间共享。
下面是显示问题的示例:
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是共享的。它对于每个特定功能来说都是本地的。
与尝试的其他方法完全相同的问题,因此此方法对我不起作用。
In C, I used to add the word static next to a variable when I define a local variable inside a function if I wanted the local variable value saved between calls.
This gave me the local scope protection of the variable name, but at the same time, the variable value was persistent. Was very useful to emulate a simple object which saves its own private state.
http://en.wikipedia.org/wiki/Local_variable#Static_local_variables
Is it possible to emulate this in Mathematica using Module[]
? or DynamicModule[]
?
(we know Module[]
does not save local variables state by default, but What about using DynamicModule[]
?)
No uses of packages. The context of using this is inside a Manipulate[]
.
No Module[]
can be outside Manipulate. Hence everything has to be something like this:
Manipulate[
foo[]:=Module[{a,b,c},....];
boo[]:=Module[{a,b,c},....];
... foo[] ..
... boo[]...
..,
control_variables...,
Initialization:>
(
.... global area....
)
]
I tried using DynamicModule
in place of Module[]
above to do this, but DynamicModules
can't be called as functions? and I could not figure how to do it.
question is: is it possible to make a function remember the value of its local variables between calls, as one can do using C with local static variables for example?
of course, one can't save the state in global variables, this the whole point of me asking this question. I'd like the Module state saved in a context that belongs to that Module only.
I am not asking for any advanced OO emulation. Just wanted to save few local variables used by a Module in a name scope that belong to that Module instead in a global context and have them be persistent between calls to the Module.
Update
To be clear, here is a very basic C example
#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
$
Update 8:45 AM
This is for WReach solution. Here is what I tried:
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}
]
The total remain 1 each time I hit the button. It is not saving the last value.
Update 9:13 AM
For WReach solution inside Manipulate:
Here is a test:
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}
)
]
)
]
On its own, it seems to work. But when I made a copy of the cell, and paste it to new cell. Then run the second Manipulate, to update the total there, then went back to the first Manipulate to update the total there, I see it is using the updated total from the second Manipulate. Hence it is global.
This is not allowed in a demo. Snap-shots are taken, and they can't share state (no global variables are allowed in a demo. The initialization section must not contain global shared data. But can contain functions that are called via parameters only from the Manipulate expression, no problem.
update 9:40 AM
Reply to Mr Wizard second example below, for the pattern he showed, which is the following:
Manipulate[
{x, myAdd[]},
{x, 1, 10},
{{total, 0}, None},
{{myAdd, (total += 1; total) &}, None}
]
The problem with this, is that the name total
can not be used by 2 different functions. The name space for total
is across the whole Manipulate. What I'd want, using this pattern is something like this:
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}
]
You see, in the above, processA has its own local total, and processB as well. Same local name. The above does not work. If I replace the above with the following to make it '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}
]
Then processA and processB now share the same total variable. This defeats the whole point of having each be in separate name space, and yet be persistent over life time of call invocations.
Update 10 AM
Opps, I had bad way to writing that Module[] in the above example. That is why it was NOT working. Please ignore my 9:40 AM update. I am correcting it now, and will update in few minutes. It might actually be working.
update 10:08 AM
Ok, here is the scoop: In my 9:40 AM when I said "the above does not work", is because I had the setup wrong, wrong place of (). I corrected this. I am now showing the solution refered to below by WReach under the title Avoiding Global Definitions
The news is that it works for ONE manipulate. Once I copy the manipulate to another cell, the counters are shared between the 2 manipulates.
Here is an example: (corrected version of what I had above in 9:40 AM)
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}
]
The set up works, as long as there is one copy of the Manipulate. Once I copy the Manipulate itself to new cell, and modify that, the first gets updated. counters are global:
So, too bad, these solution do not work for me. Will try later the function context thing. But need to learn more about it first.
update 12 PM
To illustrate what I do now, in reply to MrWizard below, for each 'solver' I have, I pre-fix the name of each of its parameters by pn
, where n
is a solver ID number. So I have p1StepNumber, p2StepNumber, p3StepNumber, p1Solution, p2Solution, p3Solution, etc...
Then when I want to call solver 1, I pass it the p1* parameters and on return it returns back the solution and any updates, to be saved in the Manipulate Control->None area for later call, and so on.
Hence, state of each solver is kept/saved inside the Manipulate as Control->None variables. Since Manipulate is DynamicModule, these are saved between calls, and even when I close M and reopen it.
Here is a screen shot of partial listing of my Manipulate parameters in the Control-None area, to illustrate. all of these and much more are in one Manipulate. When user changes solver, the whole UI changes as well with a new layout specific for that solver.
Thanks to the use of Leonid Macro method, I am able to now do this easily :).
It would be better if I can save these 'inside' each solver, and have each solver be a separate Module, where each solver will save it own state, and Manipulate will just pass it the UI parameter each time it needs to refresh, and everything else is saved inside the solver(s) where they belong.
Not having even a struct to manage this, means each call I make has over 20-30 parameters to it. Since I need to pass the solver all of its state each time, and get it back with it returns. It is not too bad, I just have to get used to making calls with 30 parameters each time, which is something I am not used. But I see no other clean way around it so far. That is why I asked this question.
update 12/24/11 6 PM
This is below response to suggestion by Szabolcs and telefunkenvf14 to use function context name.
The conclusion I found is that this method does not work either. Same issue as the other methods.
Once I make a copy of the Manipulate itself, the variables become shared among the 2 copies of the Manipulates.
Below is an example showing the problem:
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}
]
Now I copied the above into a new cell and clicked on the buttons, and I see the counters now advance from the values in the previous copy of Manipulate. So process`A is shared. It is local to each specific function.
Exactly the same issue with the other method tried, so this method does not work for me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
试试这个:
使用:
出于实际目的,模块变量
total
仅对myAdd
可见。Module
通过创建一个新的唯一符号来实现此功能,该符号的名称是根据提供的符号生成的(在本例中为total
)。您可以通过计算表达式来看到这一点,例如:我们实际上可以访问
myAdd
使用的符号:我们还可以通过检查
myAdd
的定义来查看重命名的效果:在 Manipulate 中使用
我们可以在
Manipulate
中使用这种技术,因此:避免全局定义
如果我们迫切希望避免
myAdd
的全局定义,我们可以这样做:这样,
myAdd
的定义就被本地化了在Manipulate
中。但请注意,符号myAdd
仍然是全局的,x
和total
也是如此。这是因为整个Manipulate
表达式被读入全局上下文。如果这不能令人满意,那么我们就必须将整个表达式放入另一个上下文中——无法避免符号必须存在于某些上下文中的事实。再次进入漏洞
好的,这是解决附加要求的另一种尝试:
该解决方案具有以下功能:
f
和g
的定义> 本地化到单元格total
的两次出现彼此隔离,并且本地化到单元格,时,
total
变量都不会重置为零xTry this:
Use:
For practical purposes, the module variable
total
is visible only tomyAdd
.Module
implements this by creating a new unique symbol whose name is generated from the supplied symbol (total
in this case). You can see this by evaluating an expression such as:We can actually access the symbol used by
myAdd
:We can also see the effect of the renaming by examining the definition of
myAdd
:Use Inside Manipulate
We can use this technique inside
Manipulate
thus:Avoiding Global Definitions
If we are desperate to avoid a global definition of
myAdd
, we can do this:This way, the definition of
myAdd
is localized within theManipulate
. Note, however, that the symbolmyAdd
is still global, as arex
andtotal
. This is due to the fact that the entireManipulate
expression is read into the global context. If this is unsatisfactory, then we would have to place the entire expression into another context -- there is no avoiding the fact that symbols have to live in some context.Once More Into The Breach
Okay, here is another attempt to address the added requirements:
This solution has the following features:
f
andg
are localized to the celltotal
are isolated from one another, and localized to the celltotal
variables are not reset to zero whenever you manipulatex
如果我了解您的需求,但我不确定我是否了解,那么我在这篇文章中建议的表单可能会满足您的需求:
https: //stackoverflow.com/a/8552728/618728
也就是说,使用如下控件:
{{x, 0}, None}
调整附加示例,可以执行以下操作 工作?
改编 WReach 的最新示例:
以下是使用您最新问题更新的示例。据我所知,这是有效的。我建议您找到一种方法来解决对单独符号的需求。
If I understand your needs, and I am not sure I do, then the form I suggested in this post may do what you want:
https://stackoverflow.com/a/8552728/618728
That is, using controls like:
{{x, 0}, None}
Adapting your appended example, does this work?
Adapting WReach's recent example:
Here is an example using your latest question update. As far as I can tell this works. I suggest you find a way to work around the need for separate symbols.