Especificaciones de uso y trabajo interno de las funciones * Set *

Acabo de notar una característica indocumentada del trabajo interno de*Set* funciones en Mathematica.

Considerar

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

During evaluation of In[1]:= !

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

per

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}

¿Cuál es la razón de esta diferencia? Por quéa se evalúa aunqueSet tiene atributoHoldFirst? ¿Para qué fines es útil este comportamiento?

Y tenga en cuenta también este caso:

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

omo puede ver, obtenemos la definición de trabajo para5[b] evitandoProtected atributo de la etiquetaInteger que causa errores en los casos habituales:

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

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

Out[13]= 1

La otra forma de evitar este error es usarTagSet*:

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

Out[15]= 1

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

¿Por qué son estas características?

En cuanto a mi pregunta, ¿por qué podemos escribira := (a =.; 5); a[b] = 2 mientras no puedea := (a =.; 5); a[1] = 2. En realmente en Mathematica 5 no podemos escribira := (a =.; 5); a[b] = 2 también

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

(Lo anterior se copia de Mathematica 5.2)

Podemos ver lo que sucede internamente en las nuevas versiones de Mathematica cuando evaluamosa := (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&&a,mp;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}

Me sorprendió mucho ver llamadas a Java en una operación tan pura relacionada con el lenguaje como asignar un valor a una variable. ¿Es razonable usar Java para tales operaciones?

Todd Gayley (Wolfram Research)ha explicado este comportamiento

Al principio, permítanme señalar que en Mathematica 8, J / Link ya no sobrecarga a Set. Se creó un mecanismo interno de kernel que, entre otras cosas, permite que J / Link evite la necesidad de "trucos" especiales con Set.

J / Link ha sobrecargado Set desde el principio, hace casi doce años. Esto le permite soportar esta sintaxis para asignar un valor a un campo Java:

 javaObject@field = value

La definición sobrecargada de Conjunto provoca una ralentización en las asignaciones del formulario

 _Symbol[_Symbol] = value

Por supuesto, la asignación es una operación rápida, por lo que la desaceleración es pequeña en términos reales. Es probable que solo los tipos de programas altamente especializados se vean significativamente afectados.

La sobrecarga del conjunto hacen causa una llamada a Java en tareas que no involucran objetos Java (esto sería muy costoso). Esto se puede verificar con un simple uso de TracePrint en su a [b] = c.

Como observa, hace un ligero cambio en el comportamiento de las asignaciones que coinciden con _Symbol [_Symbol] = value. Específicamente, en f [_Symbol] = value, f se evalúa dos veces. Esto puede causar problemas para el código con la siguiente forma (muy inusual):

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

No recuerdo haber visto alguna vez un código "real" como este o un problema informado por un usuario.

Todo esto es discutible ahora en 8.0.

Respuestas a la pregunta(2)

Su respuesta a la pregunta