Especificidades de uso e trabalho interno de * Definir * funções
Acabei de notar um recurso não documentado do trabalho interno de*Set*
funções em Mathematica.
Considerar
In[1]:= a := (Print["!"]; a =.; 5);
a[b] = 2;
DownValues[a]
During evaluation of In[1]:= !
Out[3]= {HoldPattern[a[b]] :> 2}
ma
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}
Qual é o motivo dessa diferença? Por quêa
é avaliado emboraSet
tem atributoHoldFirst
? Para que fins esse comportamento é útil?
E observe também 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
Como você vê, obtemos a definição de trabalho para5[b]
evitandoProtected
atributo da tagInteger
que causa erro em casos habituais:
In[13]:= 5[b] = 1
During evaluation of In[13]:= Set::write: Tag Integer in 5[b] is Protected. >>
Out[13]= 1
A outra maneira de evitar esse erro é usarTagSet*
:
In[15]:= b /: 5[b] = 1
UpValues[b]
Out[15]= 1
Out[16]= {HoldPattern[5[b]] :> 1}
Por que esses recursos?
Quanto à minha pergunta por que podemos escrevera := (a =.; 5); a[b] = 2
enquanto não pudera := (a =.; 5); a[1] = 2
. Em realmente em Mathematica 5 não podemos escrevera := (a =.; 5); a[b] = 2
também
In[1]:=
a:=(a=.;5);a[b]=2
From In[1]:= Set::write: Tag Integer in 5[b] is Protected. More...
Out[1]=
2
(O acima foi copiado de Mathematica 5.2)
Podemos ver o que acontece internamente em novas versões do Mathematica quando avaliamosa := (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}
Fiquei muito surpreso ao ver chamadas para Java em uma operação tão pura relacionada à linguagem como atribuir um valor a uma variável. É razoável usar Java para essas operaçõe
Todd Gayley (Pesquisa Wolfram)tem explicado esse comportamento
No início, deixe-me salientar que no Mathematica 8, o J / Link não sobrecarrega mais o Set. Foi criado um mecanismo interno do kernel que, entre outras coisas, permite ao J / Link evitar a necessidade de "truques" especiais com o Set.
@ J / Link sobrecarregou o Set desde o início, quase doze anos atrás. Isso permite suportar esta sintaxe para atribuir um valor a um campo Java:
javaObject@field = value
A definição sobrecarregada de Set causa uma desaceleração nas atribuições do formulário
_Symbol[_Symbol] = value
Certamente, a atribuição é uma operação rápida, portanto a desaceleração é pequena em termos reais. Somente tipos de programas altamente especializados provavelmente serão significativamente afetado
A sobrecarga do conjunto nnã causar uma chamada para Java em atribuições que não envolvem objetos Java (isso seria muito caro). Isso pode ser verificado com um simples uso do TracePrint no seu a [b] = c.
Faz, como você observa, fazer uma ligeira alteração no comportamento das atribuições que correspondem a _Symbol [_Symbol] = value. Especificamente, em f [_Symbol] = value, f é avaliado duas vezes. Isso pode causar problemas no código com o seguinte formato (altamente incomum):
f := SomeProgramWithSideEffects[]
f[x] = 42
Não me lembro de ter visto um código "real" como esse ou de um problema relatado por um usuári
gora está tudo discutido no 8.