Nas*_*ser 4 wolfram-mathematica
我喜欢使用With[]我需要在两个不同的地方使用的常量.
我没有在2个地方输入相同长的常量列表,而是试图计算如何使用这个列表的变量,然后在我想要使用列表的几个地方使用这个变量.
问题是我需要Hold列表,然后ReleaseHold在需要时间时使用它,但我无法正确使用这部分.(尝试过很多东西,对我没用)
这是一个例子:
With[{$age = 2, $salary = 3},
x = $age
]
With[{$age = 2, $salary = 3},
y = $age
]
Run Code Online (Sandbox Code Playgroud)
我不想在周围键入相同的常量(在我的情况下,这些常量非常长),我试图做这样的事情:
c = HoldForm[{$age = 2, $salary = 3}]
With[Release[c],
x = $age
]
With[Release[c],
y = $age
]
Run Code Online (Sandbox Code Playgroud)
我尝试了上面的许多其他组合.如此多的Hold*和Release*版本,我发现它们都非常令人困惑.
问题是:任何人都知道如何做到这一点,所以我可以在不止一个地方重复使用该列表而不实际复制它?
为了将其置于上下文中,以下是需要这样的示例:
我不能用WithManipulate 环绕一切:(而且我不能把With外面的操作放在我正在做的事情上,一切都必须在里面Manipulate)
Manipulate[
Evaluate@With[{$age = 2, $salary = 3},
x;
$age,
{{x, $age, "age="}, 0, 10, 1}
]
]
Run Code Online (Sandbox Code Playgroud)
语法无效.(由于","需要将Manipulate表达式与控件分开).(它现在认为有3个参数)
我当然可以
Manipulate[
With[{$age = 2, $salary = 3},
x;
$age
],
Evaluate@With[{$age = 2, $salary = 3},
{{x, $age, "age="}, 0, 10, 1}
]
]
Run Code Online (Sandbox Code Playgroud)
但是如你所见,我不得不复制常量列表.
如果我可以想出如何定义列表一次,我可以把它放在Initialization部分中Manipulate并使用它,如下所示:
Manipulate[
With[ReleaseHold[myList],
x;
$age
],
Evaluate@With[ReleaseHold[myList],
{{x, $age, "age="}, 0, 10, 1}
],
Initialization :>
(
myList = HoldAll[{$age = 2, $salary = 3}];
)
]
Run Code Online (Sandbox Code Playgroud)
我想我想做的事情是可能的,我只是无法确定用于保持/释放保持部分的正确命令.
编辑(1)
我想我举了一个例子,说明为什么我要使用常量With.
我想出了这个新方法:)让我模拟一个记录或结构.
常量值将是记录的命名字段(实际上只是一个列表).
对于字段名称,我给它一个序号,(我从1开始)然后我使用$field=number,然后在代码中,我写入 struct[[$field]]=...访问该字段.
我需要将命名字段的值共享到Manipulate表达式和控件区域之间的结构,因为两者都需要使用相同的结构.
下面是一个Manipulate的简单示例,它从UI和表达式中读取年龄和当前工资,并根据当前工资和之前的工资分配新工资.
该记录用于在控制区域与表达式和较低级别功能之间传递数据.
在我当前的演示中,我有数百个这样的参数,(我实际上现在有几个演示,所有在一个演示中,我根据在UI上选择的选项在不同的UI布局(控件)之间切换)并使用记录将简化生活对我来说,因为现在我可以进行函数调用,只传递几个参数,包含UI参数的记录,而不是100个单独的参数,这就是我现在要做的.正如我之前多次说过的,Mathematica需要一个真正的记录/结构作为基本数据结构,除了List和Array等,它们被集成到M.
(UI参数必须全部发送到较低级别的函数,除了这样做之外别无选择.我不想使用全局变量.设计不好).
我现在也可以通过引用传递此记录如果我想允许更新发生在其他更低级别的函数中.我仍然在评估这个方法,看看我是否可以在我的主代码中实际使用它.
(*verison 1.1*)
Manipulate[
With[{$age = 1, $salary = 2, $newSalary = 3},
updateRecord[record_] := Module[{},
(*update/process UI input*)
record[[$newSalary]] = record[[$salary]] + record[[$age]]*10;
(*return result*)
record
];
(*call lower level function to process UI parameters*)
myRecord = updateRecord[Unevaluated@myRecord];
(*display the result *)
Grid[{
{"age=", myRecord[[$age]]},
{"current salary=", myRecord[[$salary]]},
{"new salary=", myRecord[[$newSalary]]}
}]
],
(* build the UI controls *)
Evaluate@With[{$age = 1, $salary = 2, $newSalary = 3},
Grid[{
{"age=",
Manipulator[Dynamic[age, {age = #; myRecord[[$age]] = age} &],
{10, 100, 1}, ImageSize -> Tiny], Dynamic[age]},
{"salary=",
Manipulator[
Dynamic[salary, {salary = #; myRecord[[$salary]] = salary} &],
{10, 10000, 10}, ImageSize -> Tiny], Dynamic[salary]}
}
]
],
{{myRecord, {10, 100, 100}}, None},
{{age, 10}, None},
{{salary, 1000}, None},
TrackedSymbols -> {age, salary}
]
Run Code Online (Sandbox Code Playgroud)

编辑(2)
在尝试使用下面的Leonid时,我可以在Manipulate表达式中使用它,但无法计算如何在控件区域中使用它.
以下是With在2个地方使用的原始示例:
Manipulate[
With[{$age = 2, $salary = 3},
x + $age
],
Evaluate@With[
{$age = 2, $salary = 3},
{{x, $age, "age="}, 0, 10, 1}
],
{x, None}
]
Run Code Online (Sandbox Code Playgroud)
现在使用下面的新Leonid方法,这是我到目前为止:
Manipulate[
env[
x + $age
],
Evaluate@With[
{$age = 2, $salary = 3},
{{x, $age, "age="}, 0, 10, 1}
],
{x, None},
Initialization :>
(
ClearAll[makeCustomEnvironment];
SetAttributes[makeCustomEnvironment, HoldAll];
makeCustomEnvironment[values : (_Symbol = _) ..] :=
Function[code, With @@ Hold[{values}, code], HoldAll];
env = makeCustomEnvironment[$age = 2, $salary = 3];
)
]
Run Code Online (Sandbox Code Playgroud)
但是它也可以用于控制吗?我不能这样做:
Manipulate[
env[
x + $age
],
env[
{$age = 2, $salary = 3},
{{x, $age, "age="}, 0, 10, 1}
],
{x, None},
Initialization :>
(
ClearAll[makeCustomEnvironment];
SetAttributes[makeCustomEnvironment, HoldAll];
makeCustomEnvironment[values : (_Symbol = _) ..] :=
Function[code, With @@ Hold[{values}, code], HoldAll];
env = makeCustomEnvironment[$age = 2, $salary = 3];
)
]
Run Code Online (Sandbox Code Playgroud)
因为上面给出了很多错误.
编辑(3)
删除不正确
编辑(4)
删除了上面编辑(3)的内容,因为它包含我身边的用户错误报告问题.
以下是WRI对我收到错误原因的支持回应
Manipulate::vsform: Manipulate argument env[{{age,100,age},10,200,1}] does
not have the correct form for a variable specification. >>
Run Code Online (Sandbox Code Playgroud)
当我写下面的代码时:
Manipulate[
env[
record[[$age]] = age;
record[[$salary]] = 60*age;
{record[[$age]], record[[$salary]]}
],
env[
{{age, 100, "age"}, 10, 200, 1}
],
{{record, {40, 5}}, None},
{{salary, 40000}, None},
TrackedSymbols :> {age},
Initialization :>
(
makeCustomEnvironmentAlt =
Function[Null, Function[code, With @@ Hold[{##}, code], HoldAll],
HoldAll];
env = makeCustomEnvironmentAlt[$age = 1, $salary = 2];
)
]
Run Code Online (Sandbox Code Playgroud)
这是出现此错误原因的支持说明:
The issue is specifically with the section:
Evaluate@env[{{age, 100, "age"}, 10, 200, 1}]
Manipulate doesn't really evaluate until it gets to the Initialization
option, but it will check its input for correct form. Mathematica reads the
main body of the Manipulate before running the Initialization option. This
is can be verified by using a Print statement:
Initialization -> (Print["Test"];
makeCustomEnvironmentAlt =
Function[Null, Function[code, With @@ Hold[{##}, code], HoldAll],
HoldAll];
env = makeCustomEnvironmentAlt[$age = 1, $salary = 2];
Print["Test"])
Test does not print.
Getting around this will be probably not be clean.
....
Having the code for the controller for age depend on evaluation of
some function which must be initialized does not appear to be possible
with simply Manipulate.
Run Code Online (Sandbox Code Playgroud)
我希望这个信息帮助.感谢大家的帮助以及WRI的支持和解释.
我要做的是编写一个函数生成器来创建自定义(词法)环境:
ClearAll[makeCustomEnvironment];
SetAttributes[makeCustomEnvironment, HoldAll];
makeCustomEnvironment[values : (_Symbol = _) ..] :=
Function[code, With @@ Hold[{values}, code], HoldAll];
Run Code Online (Sandbox Code Playgroud)
这需要一个声明列表并创建一个纯函数,它在With内部使用封装的常量.我曾经With@@Hold[...]愚弄重命名机制,Function以便它不会重命名里面的变量With(而不是With,可以使用withRules@Szabolcs建议的函数,这将导致稍微不同的替换语义).
现在,我们创建自定义函数:
env = makeCustomEnvironment[$age = 2, $salary = 3];
Run Code Online (Sandbox Code Playgroud)
并像这样使用它:
In[25]:=
env[x=$age];
x
Out[26]= 2
In[27]:=
env[y=$age];
y
Out[28]= 2
Run Code Online (Sandbox Code Playgroud)
这个构造对于保存的变量(带有规则或其他)的优点是,这里我们封装行为而不是状态.这可以说是更清晰,更符合函数式编程范式(我们在这里创建一个闭包而不是实例化一个类).
编辑
显然,示威规则非常严格,不允许使用过时的代码.希望这个版本可以:
makeCustomEnvironmentAlt =
Function[Null,
Function[code, With @@ Hold[{##}, code], HoldAll],
HoldAll]
Run Code Online (Sandbox Code Playgroud)
但是你必须记住输入参数的格式(由于使用了暗示模式,这对于初始解决方案来说很清楚).