重载集[a,b](a = b)

时间:2011-05-04 15:39:32

标签: wolfram-mathematica

我想重载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

2 个答案:

答案 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不匹配,因为即使变量已存储某些structSet也只有变量名称。为了使匹配成功,Set内的变量必须评估其值。但是,该值是不可变的,您无法分配给它。我建议的代码测试变量是否具有struct[something]形式的赋值,如果是,则修改第一部分(Part命令是异常,它可以修改L的部分-value表达式,只要这些部分已经存在)。

您可以在许多地方详细了解Hold* - 属性和相关问题的相关主题,例如herehere

答案 1 :(得分:1)

我也不相信TagSet可以做到这一点,因为必须保留Set的第一个参数。

在我看来,如果修改Set,可以通过以下方式完成:

Unprotect[Set]

Set[s_, x_] /; Head[s] === struct := s[[1]] = x

然而,Leonid比我更了解Mathematica,他可能有更好的理由来定义更长的时间。