xzh*_*zhu 23 wolfram-mathematica
对我来说,g /: f[g[x_]] := h[x]只是冗长等同于f[g[x_]] := h[x].你能提出一个你必须使用的例子/:吗?
rco*_*yer 29
实际上,g /: f[g[x_]] := h[x]并不等同于f[g[x_]] := h[x].后者与相关联的定义f,而TagSet(/:)和UpSet(^=和它的延迟版本,^:=)与定义关联g.这是一个至关重要的区别,可以通过一个简单的例子来说明.假设你想拥有一组服从模5加法的变量,即6 + 7 mod 5 = 3.所以,我们希望任何东西Head mod都能正常运行.最初,我们认为
a_mod + b_mod := mod@Mod[a + b, 5]
Run Code Online (Sandbox Code Playgroud)
会工作.但是,它会产生错误
SetDelayed::write : Tag Plus in a_mod + b_mod is Protected.
Run Code Online (Sandbox Code Playgroud)
我们可以删除Unprotect Plus,然后我们的定义会起作用,但这可能会导致其他定义出现问题,并且随着Plus累积更多定义,它会变慢.或者,我们可以通过添加属性与mod对象本身相关联TagSet
mod /: a_mod + b_mod := mod @ Mod[a + b, 5]
Run Code Online (Sandbox Code Playgroud)
要么 UpSetDelayed
a_mod + b_mod ^:= mod @ Mod[a + b, 5]
Run Code Online (Sandbox Code Playgroud)
从概念的角度来看,设置upvalue更正确,因为mod具有不同属性的那个.
有几个问题需要注意.首先,upvalue机制只能扫描一个级别,即Plus[a_mod, b_mod]很好,但Exp[Plus[a_mod, b_mod]]会引发错误.这可能需要您使用中间类型进行创作.其次,从编码的角度来看UpSetDelayed,编写起来比较容易,但偶尔会出现一些含糊不清Head的问题. TagSet通过明确命名适当的来处理它Head,一般来说,这是我更喜欢的UpSet.
Mathematica的一些操作符没有任何与之相关的行为,因此它们不受保护.对于这些运算符,您可以根据需要定义函数.例如,我已经定义了
a_ \[CircleTimes] b_ := KroneckerProduct[a,b]
a_ \[CircleTimes] b_ \[CircleTimes] c__ := a \[CircleTimes] ( b \[CircleTimes] c )
Run Code Online (Sandbox Code Playgroud)
和
a_ \[CirclePlus] b__ := BlockDiagonal[{a,b}]
Run Code Online (Sandbox Code Playgroud)
为我经常使用的矩阵运算提供方便的简写符号.
我上面的例子有点做作,但有很多次UpValues派上用场了.例如,我发现我需要一种符号形式,用于在乘法和幂运算中表现得恰当的复杂统一根.
示例:一个简单而有用的示例将a标记Symbol为Real:
makeReal[a__Symbol] := (
# /: Element[#, Reals] := True;
# /: Im[#] := 0;
# /: Re[#] := #;
# /: Abs[#] := Sign[#] #;
# /: Arg[#] := Piecewise[{{0, Sign[#] >= 0}, {Pi, Sign[#] < 0}}]
) & /@ List[a]
Run Code Online (Sandbox Code Playgroud)
注意使用TagSetas Element[ a, Reals ] ^:= True可能不明确.该规则将附加什么a或Reals?此外,如果我们想要一个正实数,我们可以设置Arg[#]:=0哪个允许Simplify按预期运行,例如Simplify[Sqrt[a^2]] == a.
Leo*_*rin 16
除了@rcollyer的优秀答案之外,我还想强调一些其他重要的事情UpValues.
一个非常重要的方面是它们允许您仅在某些符号上"轻柔地"重载某些系统功能.@rcollyer指出了这一点的重要性,但不能过分强调 - 这会使代码本地化,并大大降低代码可以全局交互并影响系统的其他部分或其他部分的机会.用户定义的代码,与Unprotect系统符号不同,并添加一些代码DownValues.
除了安全和本地之外,如果使用类似的结构,这种重新定义也可能非常普遍yourSymbol/:f_[_yourSymbol,rest___]:=....这些应该谨慎使用,但有时可以提供非常简洁和简单的解决方案.下面是一个示例,其中一个代码可以用于一次"重载"多个系统函数,为它们提供额外的非平凡功能.
下一点是评估.您可以遇到的常见声明是" UpValues之前应用DownValues".这必须明确:对于f[g[args]]这意味着UpValues对于g之前申请DownValues的f,前提是评估过程中已经去所有他们的方式"下"到最里面的部分,然后回到"上升".特别是,它并不意味着UpValues对g将之前施加DownValues用于g-如果g[args]可以评估内部f因为g具有适度的DownValues,它会(除非f有所述之一Hold-attributes),和存在UpValues不会阻止,因为(用于标准评估),评估g[args]之前发生的评估f[result-of-evaluation-of g[args]].例如,这里:
In[58]:=
ClearAll[f, g];
f[x_] := x^2;
g /: f[g[x_]] := Sin[g[x]];
g[x_] := Cos[x];
In[62]:= f[g[y]]
Out[62]= Cos[y]^2
Run Code Online (Sandbox Code Playgroud)
在UpValues为g没有机会用到,因为g[y]转化为Cos[y]在前面的评估步骤.这种情况将是非标准评价不同-或者,如果我们给f的属性HoldAll或者HoldFirst,或者,如果我们总结g[y]的Unevaluated-在这两种情况下,我们给评价者的指令跳过的评价g[y]:
In[63]:= f[Unevaluated[g[y]]]
Out[63]= Sin[Cos[y]]
Run Code Online (Sandbox Code Playgroud)
这一点与前一点有关:应该意识到搜索UpValues甚至在具有Hold- 属性的头部内执行,因此,UpValue即使DownValue基于相似外观的定义也不会,也可以评估基于定义的定义.例:
In[64]:= ClearAll[f,ff];
f[x_]:=Print["Evaluated"];
ff/:h_[ff[x_]]:=Print["Evaluated"];
In[67]:= Hold[f[1]]
Out[67]= Hold[f[1]]
In[68]:= Hold[ff[1]]
During evaluation of In[68]:= Evaluated
Run Code Online (Sandbox Code Playgroud)
如果一个人想要绝对阻止搜索UpValues,那么应该给一个函数HoldAllComplete属性.例如:
In[69]:= {HoldComplete[f[1]],HoldComplete[ff[1]]}
Out[69]= {HoldComplete[f[1]],HoldComplete[ff[1]]}
Run Code Online (Sandbox Code Playgroud)
这已经被@rcollyer提到了.引入了该限制以用于模式匹配器/评估器的效率.我只想强调它的一个重要且非显而易见的结果:看起来你不能使用UpValues重载赋值(Set运算符),以便它可以处理分配给你引入的某些特定类型的对象的变量.这是一个尝试:
In[74]:=
ClearAll[a,myType,myCustomCode,newValue];
myType/:Set[var_myType,rhs_]:=myCustomCode;
Run Code Online (Sandbox Code Playgroud)
这似乎有效.但是让我们试试:
In[79]:= a = myType[1, 2, 3];
a = newValue;
a
Out[81]= newValue
Run Code Online (Sandbox Code Playgroud)
显然,它没有做我们想要的.问题是Set保持它的lhs,所以当模式匹配发生时,它只有符号a,而不是它的值.并且因为我们无法将定义与标签更深层次关联,而不是表达式的第一层,所以以下内容也不起作用:
ClearAll[a,myType,myCustomCode,newValue];
myType/:Set[var_,rhs_]/;MatchQ[var,_myType]:=myCustomCode;
TagSetDelayed::tagpos: Tag myType in (var_=rhs_)/;MatchQ[var,_myType]
is too deep for an assigned rule to be found. >>
Run Code Online (Sandbox Code Playgroud)
据我所知,UpValues不能用来解决这个问题,这是一个遗憾,因为=对于各种数据类型具有自定义分配代码的通常语法将是方便的.有关类似的讨论,请参阅此帖子.这种情况并不是唯一的Set- 对于任何包含您想要用于UpValue基于定义的参数的函数都是如此.
UpSet和TagSet,UpSetDelayed和TagSetDelayed值得一提的是,当您使用UpSet或时UpSetDelayed, 第1级的所有标签都会获得其他定义(规则).例如:
Clear[a,b];
Plus[a,b]^:=1;
?a
Global`a
a/:a+b:=1
?b
Global`b
b/:a+b:=1
Run Code Online (Sandbox Code Playgroud)
与此相反,TagSet和TagSetDelayed更加精确:
ClearAll[a,b];
a/:Plus[a,b]:=1;
?a
Global`a
a/:a+b:=1
?b
Global`b
Run Code Online (Sandbox Code Playgroud)
根据我的经验,后一种行为通常更为可取,所以在大多数情况下我更喜欢TagSet或TagSetDelayed过度UpSet或UpSetDelayed.
Rcollyer已经给出了一个很好的答案,但这里有一个例子,说明你何时可以使用UpValues:当你定义一个特定的数据结构时,它有自己的Head,并且你想要定义内置的算法如算术的结构.我曾经为timeSeries数据结构做过这样的事情,例如,添加将匹配第一列中的日期,并在第二列中添加相应的值对.如果您未使用a定义此类操作,则在第一列中添加带有日期的T*2向量将给出无意义的日期UpValue.
| 归档时间: |
|
| 查看次数: |
2880 次 |
| 最近记录: |