我想重载Mathematica的Set函数(=),这对我来说太棘手了(参见下面的代码示例)。我成功地重载了其他函数(例如代码示例中的Reverse)。有什么建议吗?
In[17]:= ClearAll[struct];
In[18]:= var1=struct[{1,2}]
Out[18]= struct[{1,2}]
In[19]:= Reverse@var1
Out[19]= struct[{1,2}]
In[20]:= Head[var1]
Out[20]= struct
In[21]:= struct/:Reverse[stuff_struct]:=struct[Reverse@stuff[[1]]]
In[22]:= Reverse@var1
Out[22]= struct[{2,1}]
In[23]:= struct/:Set[stuff_struct,rhs_]:=Set[struct[[1]],rhs]
In[24]:= var1="Success!"
Out[24]= Success!
In[25]:= var1
Out[25]= Success!
In[26]:= Head[var1]
Out[26]= String
In[27]:= ??struct
Global`struct
Reverse[stuff_struct]^:=struct[Reverse[stuff[[1]]]]
(stuff_struct=rhs_)^:=struct[[1]]=rhs
答案 0 :(得分:8)
我不认为你想要的是UpValues
(唉),因为符号(标签)必须不比第一级深,才能使定义工作。此外,您想要的语义在Mathematica中有点不寻常,因为大多数Mathematica表达式是不可变的(不是L值),并且它们的部分不能被赋值。我相信这段代码会做你想做的事情:
Unprotect[Set];
Set[var_Symbol, rhs_] /;
MatchQ[Hold[var] /. OwnValues[var], Hold[_struct]] := Set[var[[1]], rhs];
Protect[Set];
例如:
In[33]:= var1 = struct[{1, 2}]
Out[33]= struct[{1, 2}]
In[34]:= var1 = "Success!"
Out[34]= "Success!"
In[35]:= var1
Out[35]= struct["Success!"]
但一般情况下,不建议将DownValues
添加到Set
等重要命令,因为这可能会以微妙的方式破坏系统。
修改强>
扩展了尝试失败的原因:Mathematica使用参数保持机制实现流控制和赋值运算符(Hold*
- 属性,描述为here)。该机制允许它特别模仿分配所需的传递引用语义。但是,当您分配到var1
时,Set
不知道var1
中已存储的内容,因为它只有符号var1
,而不是其值。模式_struct
不匹配,因为即使变量已存储某些struct
,Set
也只有变量名称。为了使匹配成功,Set
内的变量必须评估其值。但是,该值是不可变的,您无法分配给它。我建议的代码测试变量是否具有struct[something]
形式的赋值,如果是,则修改第一部分(Part
命令是异常,它可以修改L的部分-value表达式,只要这些部分已经存在)。
答案 1 :(得分:1)
我也不相信TagSet
可以做到这一点,因为必须保留Set
的第一个参数。
在我看来,如果修改Set
,可以通过以下方式完成:
Unprotect[Set]
Set[s_, x_] /; Head[s] === struct := s[[1]] = x
然而,Leonid比我更了解Mathematica,他可能有更好的理由来定义更长的时间。