【发布时间】:2011-05-01 05:52:51
【问题描述】:
我刚刚注意到 Mathematica 中 *Set* 函数内部工作的一个未记录的特性。
考虑:
In[1]:= a := (Print["!"]; a =.; 5);
a[b] = 2;
DownValues[a]
During evaluation of In[1]:= !
Out[3]= {HoldPattern[a[b]] :> 2}
但是
In[4]:= a := (Print["!"]; a =.; 5);
a[1] = 2;
DownValues[a]
During evaluation of In[4]:= !
During evaluation of In[4]:= Set::write: Tag Integer in 5[1] is Protected. >>
Out[6]= {HoldPattern[a[b]] :> 2}
造成这种差异的原因是什么?为什么a 被评估,尽管Set 具有属性HoldFirst?这种行为对哪些目的有用?
还要注意这种情况:
In[7]:= a := (Print["!"]; a =.; 5)
a[b] ^= 2
UpValues[b]
a[b]
During evaluation of In[7]:= !
Out[8]= 2
Out[9]= {HoldPattern[5[b]] :> 2}
Out[10]= 2
如您所见,我们得到了5[b] 的工作定义,避免了标签Integer 的Protected 属性,这在通常情况下会导致错误:
In[13]:= 5[b] = 1
During evaluation of In[13]:= Set::write: Tag Integer in 5[b] is Protected. >>
Out[13]= 1
避免此错误的另一种方法是使用TagSet*:
In[15]:= b /: 5[b] = 1
UpValues[b]
Out[15]= 1
Out[16]= {HoldPattern[5[b]] :> 1}
为什么会有这些功能?
关于我的问题,为什么我们可以写a := (a =.; 5); a[b] = 2 而不能写a := (a =.; 5); a[1] = 2。在 Mathematica 5 中,我们也不能写 a := (a =.; 5); a[b] = 2:
In[1]:=
a:=(a=.;5);a[b]=2
From In[1]:= Set::write: Tag Integer in 5[b] is Protected. More...
Out[1]=
2
(以上是从Mathematica 5.2复制而来)
当我们评估 a := (a =.; 5); a[b] = 2 时,我们可以看到 Mathematica 的新版本内部发生了什么:
In[1]:= a:=(a=.;5);
Trace[a[b]=2,TraceOriginal->True]
Out[2]= {a[b]=2,{Set},{2},a[b]=2,{With[{JLink`Private`obj$=a},RuleCondition[$ConditionHold[$ConditionHold[JLink`CallJava`Private`setField[JLink`Private`obj$[b],2]]],Head[JLink`Private`obj$]===Symbol&&StringMatchQ[Context[JLink`Private`obj$],JLink`Objects`*]]],{With},With[{JLink`Private`obj$=a},RuleCondition[$ConditionHold[$ConditionHold[JLink`CallJava`Private`setField[JLink`Private`obj$[b],2]]],Head[JLink`Private`obj$]===Symbol&&StringMatchQ[Context[JLink`Private`obj$],JLink`Objects`*]]],{a,a=.;5,{CompoundExpression},a=.;5,{a=.,{Unset},a=.,Null},{5},5},RuleCondition[$ConditionHold[$ConditionHold[JLink`CallJava`Private`setField[5[b],2]]],Head[5]===Symbol&&StringMatchQ[Context[5],JLink`Objects`*]],{RuleCondition},{Head[5]===Symbol&&StringMatchQ[Context[5],JLink`Objects`*],{And},Head[5]===Symbol&&StringMatchQ[Context[5],JLink`Objects`*],{Head[5]===Symbol,{SameQ},{Head[5],{Head},{5},Head[5],Integer},{Symbol},Integer===Symbol,False},False},RuleCondition[$ConditionHold[$ConditionHold[JLink`CallJava`Private`setField[5[b],2]]],False],Fail},a[b]=2,{a[b],{a},{b},a[b]},2}
看到对 Java 的调用以纯粹的与语言相关的操作(例如为变量赋值)时,我感到非常惊讶。使用 Java 进行此类操作是否合理?
Todd Gayley(Wolfram Research)has explained 这种行为:
首先,让我指出,在 Mathematica 8, J/Link 不再 重载集。内部内核 建立机制,其中 其他事情,允许 J/Link 避免 需要特殊的,呃,“技巧” 与集合。
J/Link 从 一开始,将近十二年 前。这允许它支持这个 为 Java 赋值的语法 字段:
javaObject@field = valueSet 的重载定义 导致任务的放缓 表格
_Symbol[_Symbol] = value当然,分配很快 操作,所以减速很小 实际条款。只有高度专业化 程序类型可能是 受到很大影响。
Set 重载不会导致 调用 Java 的任务 不涉及 Java 对象(这将 非常昂贵)。这可以验证 通过简单地使用 TracePrint on 你的 a[b]=c。
正如您所注意到的,它确实使 作业行为的改变 匹配 _Symbol[_Symbol] = 值。 具体来说,在 f[_Symbol] = value, f 被评估两次。这可能导致 以下代码的问题 (非常不寻常的)形式:
f := SomeProgramWithSideEffects[] f[x] = 42我不记得曾经见过“真实” 像这样的代码,或者看到问题 由用户举报。
在 8.0 中这一切都没有实际意义。
【问题讨论】:
-
在我走之前,在阅读了你的最新更新之后,我只能说:那是什么鬼?大声笑
-
我无法在 v8 中重现此行为。两个评估都会生成消息
-
@Sasha 我使用 v.7.01。顺便说一句,你通过评估
DownValues[Set]得到什么?我得到{HoldPattern[ JLink`Private`sym_Symbol[JLink`Private`arg_Symbol] = JLink`Private`val_] :> With[{JLink`Private`obj = JLink`Private`sym}, JLink`CallJava`Private`setField[ JLink`Private`obj[JLink`Private`arg], JLink`Private`val] /; Head[JLink`Private`obj] === Symbol && StringMatchQ[Context[JLink`Private`obj], "JLink`Objects`*"]]}。 -
DownValues[Set]在 Mma 8.0.1 中返回一个空列表。您显示的定义实现了对象字段分配的 JLink 语法,例如obj@field = value。在 Mma 8 中,要么 JLink 现在以另一种方式执行此操作,要么规则已移到读取保护的幕后。