操纵语句中的表达式评估

pha*_*234 3 wolfram-mathematica

我在Manipulate使用分配给应该在Manipulate语句中评估的变量的代码时遇到了问题.这是怎么回事......

test1={a,b,c};
Manipulate[test1,{a,0,10,.1},{b,0,10,.1},{c,0,10,.1}]
Run Code Online (Sandbox Code Playgroud)

操纵输出1

所以{a, b, c}没有更新.好吧,无论如何,让我们强制执行test1的评估

Manipulate[Evaluate[test1],{a,0,10,.1},{b,0,10,.1},{c,0,10,.1}]
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

现在它有效.但是如果我想绘制操纵元素的列表,就像这样

Manipulate[ListPlot[Evaluate[test1]],{a,0,10,.1},{b,0,10,.1},{c,0,10,.1}]
Manipulate[Evaluate[ListPlot[test1]],{a,0,10,.1},{b,0,10,.1},{c,0,10,.1}]
Run Code Online (Sandbox Code Playgroud)

我结束了

在此输入图像描述

两个追逐.

我知道在Mathematica的文档中"评估Dynamic或Manipulate中的表达式",但我很确定它不能解决我的问题.

Sim*_*mon 8

所以问题在于它test1是根据全局变量定义的Global`a,但是a操作中定义的是由a创建的DynamicModule,因此是本地的.这就是acl在他的Hold[a]例子中所表现出来的.

也许修复此问题的最简单方法是使用With插入test1操作:

Clear[a, b, c]
test1 = {a, b, c};
With[{test1 = test1}, 
     Manipulate[test1, {a, 0, 10, .1}, {b, 0, 10, .1}, {c, 0, 10, .1}]]
Run Code Online (Sandbox Code Playgroud)

这种方式Manipulate从未实际看到test1,它所看到的只是{a,b,c}它继续正确本地化.虽然如果a,b,cManipulate运行之前给出了一个值,这将遇到问题- 因此Clear[a,b,c]命令.

我认为最佳实践是在操作中使所有局部变量完全显式.所以你应该做点什么

Clear[a, b, c, test1]
test1[a_, b_, c_] := {a, b, c};
Manipulate[test1[a, b, c], {a, 0, 10, .1}, {b, 0, 10, .1}, {c, 0, 10, .1}]
Run Code Online (Sandbox Code Playgroud)

这可以避免您遇到的全局变量和局部变量的问题.当您必须再次回来阅读自己的代码时,它也会让您更轻松.


编辑以回答评论中的问题 "我真的想了解为什么Evaluate不适用于有点嵌套的ListPlot?" .IANLS(我不是Leonid Shifrin)所以我的大脑中没有完美的Mathematica()标准评估序列,但我会尝试解释发生了什么.

好吧,不像Plot,ListPlot不需要本地化任何变量,所以它没有Attribute HoldAll.

让我们定义类似于你的例子:

ClearAll[a, test]
test = {a, a + 1};
Run Code Online (Sandbox Code Playgroud)

你给出的最后一个例子

Manipulate[Evaluate[ListPlot[test]], {a, 0, 1}]
Run Code Online (Sandbox Code Playgroud)

通过查看Trace,您会看到这首先评估第一个参数,ListPlot[test] ~> ListPlot[{a,a+1}] 因为a它尚未本地化,它会生成一个空列表图.要看到这一点,只需运行即可

ListPlot[{a, a + 1}]//InputForm
Run Code Online (Sandbox Code Playgroud)

获取空图形对象

Graphics[{}, {AspectRatio -> GoldenRatio^(-1), Axes -> True, AxesOrigin -> {0, 0}, PlotRange -> {{0., 0.}, {0., 0.}}, PlotRangeClipping -> True, PlotRangePadding -> {Scaled[0.02], Scaled[0.02]}}]
Run Code Online (Sandbox Code Playgroud)

由于符号值a已被抛弃,它们无法通过本地化进行本地化Manipulate,因此没有太多其他事情发生.

这可以通过仍然评估第一个参数来修复,但是ListPlot直到事后才调用Manipulate变量.例如,以下两项工作

Manipulate[Evaluate[listPlot[test]], {a, 0, 1}] /. listPlot -> ListPlot
Manipulate[Evaluate[Hold[ListPlot][test]], {a, 0, 1}] // ReleaseHold
Run Code Online (Sandbox Code Playgroud)

事实上,ListPlot即使没有最轻微的抱怨就抛弃了非数字值,这可能是一个特征,但可能导致一些烦人的难以追踪的错误(就像这个问题所涉及的那样).ListPlot如果绘图值是非数字的,那么更一致(但不太有用?)的行为可能会返回未评估的行为......或者至少发出警告,表明某些非数字点已被丢弃.

你给出的倒数第二个例子是(更多?)有趣,它看起来像

Manipulate[ListPlot[Evaluate[test]], {a, 0, 1}]
Run Code Online (Sandbox Code Playgroud)

现在因为Manipulate有了属性HoldAll,它所做的第一件事就是将参数包装起来Hold,所以如果你看一下Trace,你就会看到Hold[ListPlot[Evaluate[test]]]被带走了.该Evaluate 是没有看到,因为在描述可能出现的问题部分,"仅在第一级评估工作,直接在保持功能里面".这意味着test直到变量被本地化之后才进行评估,因此它们被视为全局变量a而不是local(DynamicModule)a.

值得思考以下变体如何工作

ClearAll[a, test, f, g]
SetAttributes[g, HoldAll];
test = {a, a + 1};

Grid[{
  {Manipulate[test, {a, 0, 1}], Manipulate[Evaluate[test], {a, 0, 1}]},
  {Manipulate[f[test], {a, 0, 1}], 
   Manipulate[f[Evaluate[test]], {a, 0, 1}]},
  {Manipulate[g[test], {a, 0, 1}], 
   Manipulate[g[Evaluate[test]], {a, 0, 1}]}
  }]
Run Code Online (Sandbox Code Playgroud)

布雷恩佩恩