* Set *函数的用法和内部工作的细节

时间:2011-05-01 05:52:52

标签: wolfram-mathematica

我刚刚注意到 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]的工作定义,以避免标记Protected的{​​{1}}属性,这会在通常情况下导致错误:

Integer

避免此错误的另一种方法是使用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。在 Mathematica 5中,我们也不能写a := (a =.; 5); a[1] = 2

a := (a =.; 5); a[b] = 2

(以上内容摘自 Mathematica 5.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 内部会发生什么:

a := (a =.; 5); a[b] = 2

我很惊讶地看到在与语言相关的纯操作中调用Java,如为变量赋值。完全使用Java进行此类操作是否合理?


Todd Gayley(Wolfram Research)has explained这种行为:

  

一开始,让我指出一下   Mathematica 8,J / Link不再   重载设置。内核   其中创造了一种机制   其他的东西,允许J / Link避免   需要特殊的,呃,“技巧”   与Set。

     

J / Link已经重载了Set   一开始,差不多十二年了   前。这允许它支持这一点   用于为Java分配值的语法   字段:

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}
     

Set的重载定义   导致任务减速放缓   表格

 javaObject@field = value
     

当然,任务很快   操作,所以减速很小   实际条款。只有高度专业化   程序的类型可能是   受到严重影响。

     

Set重载导致a   在有关的任务上调用Java   不涉及Java对象(这会   非常昂贵)。这可以验证   只需使用TracePrint即可   你的a [b] = c。

     

正如你所注意到的那样   改变作业的行为   匹配_Symbol [_Symbol] =值。   具体来说,在f [_Symbol] = value,f   得到两次评估。这可能会导致   具有以下代码的问题   (非常不寻常)形式:

 _Symbol[_Symbol] = value
     

我不记得曾见过“真实”   像这样的代码,或者看到问题   用户报告。

     

现在8.0版本都没有了。

2 个答案:

答案 0 :(得分:3)

首先考虑UpSet的情况,这是预期的行为。人们可以写:

 5[b] ^= 1

分配是b而不是整数5

关于SetSetDelayed,虽然它们具有Hold属性,但它们仍在内部评估表达式。这允许以下内容:

p = n : (_List | _Integer | All);

f[p] := g[n]

测试:

f[25]
f[{0.1, 0.2, 0.3}]
f[All]
   g[25]
   g[{0.1, 0.2, 0.3}]
   g[All]

可以看到头部区域也进行了评估。这至少对UpSet

很有用
p2 = head : (ff | gg);
p2[x] ^:= Print["Echo ", head];

ff[x]
gg[x]
  

Echo ff

     

Echo gg

很容易看出它也发生在Set上,但对我来说不太清楚这是如何有用的:

j = k;
j[5] = 3;
DownValues[k]

(* Out=  {HoldPattern[k[5]] :> 3}  *)

我对你问题第一部分的分析是错误的。我现在无法理解为什么a[b] = 2被接受而a[1] = 2不被接受。也许在分配的某个阶段,第二个显示为5[1] = 2,并且模式检查会引发错误,因为LHS上没有符号。

答案 1 :(得分:3)

您显示的行为似乎是在Mathematica 8中修复的7.0.1(可能更早)中的错误。在Mathematica 8中,您的原始a[b] = 2a[1] = 2示例都给出了Set::write ... is protected错误。

问题似乎源于您确定的与{J}相关的Set下限值。该规则实现了用于为Java对象的字段赋值的JLink语法,例如, object@field = value

Mathematica 8中的

Set没有那个定义。我们可以强行重新添加类似的定义,因此:

Unprotect[Set]
HoldPattern[sym_Symbol[arg_Symbol]=val_] :=
  With[{obj=sym}
  , setField[obj[arg], val] /; Head[obj] === Symbol && StringMatchQ[Context[obj],"Something`*"]
  ]

在Mathematica 8中安装此定义后,它现在表现出与Mathematica 7中相同的不一致行为。

我认为现在通过其他方式完成JLink对象字段分配。有问题的规则看起来可能会对表单Head的每个评估添加代价高昂的StringMatchQa[b] = ...测试。好摆脱?