*Set*函数的使用和内部工作细节 [英] Specifics of usage and internal work of *Set* functions

查看:20
本文介绍了*Set*函数的使用和内部工作细节的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚注意到 Mathematica*Set* 函数内部工作的一个未记录的特性.

考虑:

In[1]:= a := (Print["!"]; a =.; 5);[b] = 2;向下值[a]在评估 In[1]:= 期间!Out[3]= {HoldPattern[a[b]] :>2}

但是

In[4]:= a := (Print["!"]; a =.; 5);[1] = 2;向下值[a]在评估 In[4]:= 期间!在评估 In[4]:= Set::write: 5[1] 中的标记整数是受保护的.>>Out[6]= {HoldPattern[a[b]] :>2}

造成这种差异的原因是什么?尽管 Set 具有属性 HoldFirst,但为什么要计算 a?这种行为对哪些目的有用?

还要注意这种情况:

In[7]:= a := (Print["!"]; a =.; 5)[b] ^= 2上值[b][b]在评估 In[7]:= 期间!出[8]= 2Out[9]= {HoldPattern[5[b]] :>2}出[10]= 2

如您所见,我们得到了 5[b] 的工作定义,避免了通常会导致错误的标签 IntegerProtected 属性案例:

输入[13]:= 5[b] = 1在评估 In[13]:= Set::write: 5[b] 中的标记整数是受保护的.>>出[13]= 1

避免此错误的另一种方法是使用TagSet*:

In[15]:= b/: 5[b] = 1上值[b]出[15]= 1Out[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 也是:

输入[1]:=a:=(a=.;5);a[b]=2From In[1]:= Set::write: Tag Integer in 5[b] is Protected.更多的...输出[1]=2

(以上复制自Mathematica 5.2)

当我们评估 a := (a =.; 5); 时,我们可以看到在新版本的 Mathematica 内部发生了什么.a[b] = 2:

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},规则条件on[$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 研究)已解释 这种行为:

<块引用>

首先,让我指出Mathematica 8, J/Link 不再重载设置.内部内核建立了机制,其中其他事情,允许 J/Link 避免需要特殊的,呃,技巧"与设置.

J/Link 已经从一开始,将近十二年前.这允许它支持这个为 Java 赋值的语法字段:

 javaObject@field = value

Set 的重载定义导致分配放缓表格

 _Symbol[_Symbol] = 值

当然,赋值是一个快操作,所以减速很小实际条款.只有高度专业化程序类型可能是受到明显影响.

Set 重载不会导致在执行任务时调用 Java不涉及 Java 对象(这将非常昂贵).这个可以验证简单地使用 TracePrint你的 a[b]=c.

正如你所指出的,它确实会产生轻微的影响任务行为的改变匹配 _Symbol[_Symbol] = 值.具体来说,在 f[_Symbol] = value 中,f被评估两次.这会导致以下代码的问题(极不寻常的)形式:

 f := SomeProgramWithSideEffects[]f[x] = 42

我不记得曾经看过真实"像这样的代码,或者看到一个问题由用户报告.

这一切在 8.0 中都没有实际意义.

解决方案

首先以 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}]落下]

 g[25]

 g[{0.1, 0.2, 0.3}]

 g[全部]

可以看到头部区域也进行了评估.这至少对 UpSet 很有用:

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

<块引用>

回声关闭

回声gg

很容易看出它也发生在 Set 中,但我不太清楚这会有什么用处:

j = k;j[5] = 3;向下值[k](* Out= {HoldPattern[k[5]] :> 3} *)

<小时>

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

I just noticed one undocumented feature of internal work of *Set* functions in Mathematica.

Consider:

In[1]:= a := (Print["!"]; a =.; 5);
a[b] = 2;
DownValues[a]

During evaluation of In[1]:= !

Out[3]= {HoldPattern[a[b]] :> 2}

but

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}

What is the reason for this difference? Why a is evaluated although Set has attribute HoldFirst? For which purposes such behavior is useful?

And note also this case:

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

As you see, we get the working definition for 5[b] avoiding Protected attribute of the tag Integer which causes error in usual cases:

In[13]:= 5[b] = 1

During evaluation of In[13]:= Set::write: Tag Integer in 5[b] is Protected. >>

Out[13]= 1

The other way to avoid this error is to use TagSet*:

In[15]:= b /: 5[b] = 1
UpValues[b]

Out[15]= 1

Out[16]= {HoldPattern[5[b]] :> 1}

Why are these features?


Regarding my question why we can write a := (a =.; 5); a[b] = 2 while cannot a := (a =.; 5); a[1] = 2. In really in Mathematica 5 we cannot write a := (a =.; 5); a[b] = 2 too:

In[1]:=
a:=(a=.;5);a[b]=2
From In[1]:= Set::write: Tag Integer in 5[b] is Protected. More...
Out[1]=
2

(The above is copied from Mathematica 5.2)

We can see what happens internally in new versions of Mathematica when we evaluate a := (a =.; 5); a[b] = 2:

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}

I was very surprised to see calls to Java in such a pure language-related operation as assigning a value to a variable. Is it reasonable to use Java for such operations at all?


Todd Gayley (Wolfram Research) has explained this behavior:

At the start, let me point out that in Mathematica 8, J/Link no longer overloads Set. An internal kernel mechanism was created that, among other things, allows J/Link to avoid the need for special, er, "tricks" with Set.

J/Link has overloaded Set from the very beginning, almost twelve years ago. This allows it support this syntax for assigning a value to a Java field:

 javaObject@field = value

The overloaded definition of Set causes a slowdown in assignments of the form

 _Symbol[_Symbol] = value

Of course, assignment is a fast operation, so the slowdown is small in real terms. Only highly specialized types of programs are likely to be significantly affected.

The Set overload does not cause a call to Java on assignments that do not involve Java objects (this would be very costly). This can be verified with a simple use of TracePrint on your a[b]=c.

It does, as you note, make a slight change in the behavior of assignments that match _Symbol[_Symbol] = value. Specifically, in f[_Symbol] = value, f gets evaluated twice. This can cause problems for code with the following (highly unusual) form:

 f := SomeProgramWithSideEffects[]
 f[x] = 42

I cannot recall ever seeing "real" code like this, or seeing a problem reported by a user.

This is all moot now in 8.0.

解决方案

Taking the case of UpSet first, this is expected behavior. One can write:

 5[b] ^= 1

The assignment is made to b not the Integer 5.

Regarding Set and SetDelayed, while these have Hold attributes, they still internally evaluate expressions. This allows things such as:

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

f[p] := g[n]

Test:

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

   g[25]

   g[{0.1, 0.2, 0.3}]

   g[All]

One can see that heads area also evaluated. This is useful at least for UpSet:

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

ff[x]
gg[x]

Echo ff

Echo gg

It is easy to see that it happens also with Set, but less clear to me how this would be useful:

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

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


My analysis of the first part of your question was wrong. I cannot at the moment see why a[b] = 2 is accepted and a[1] = 2 is not. Perhaps at some stage of assignment the second one appears as 5[1] = 2 and a pattern check sets off an error because there are no Symbols on the LHS.

这篇关于*Set*函数的使用和内部工作细节的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆