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

Wolfram mathematica 重载集[a,b](a=b),wolfram-mathematica,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

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

我不认为你想用
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*
-attributes,如上所述)实现流控制和赋值运算符。这种机制特别允许它模仿赋值所需的按引用传递语义。但是,当您分配给
var1
时,
Set
不知道
var1
中存储了什么,因为它只有符号
var1
,而没有其值。模式
\u struct
不匹配,因为即使变量已经存储了一些
struct
Set
也只有变量名。要使匹配成功,必须将
Set
中的变量计算为其值。但是,该值是不可变的,您不能将其赋值。我建议的代码测试变量是否具有
struct[something]
形式的赋值,如果是,则修改第一部分(
part
命令是一个例外,它可以修改L值表达式的部分,前提是这些部分已经存在)


您可以在许多地方阅读更多关于
Hold*
-属性和相关问题的主题,例如,

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

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

Unprotect[Set]

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

然而,莱昂尼德比我更了解Mathematica,他可能有一个很好的理由来解释更长的定义。

欢迎来到StackOverflow,phantomas1234!“phantomas1234:会员1年2个月”“LeonidShifrin:会员3个月”lol@Tomalak哎呀。。。我想应该是另一种方式:)哇,太快了。我也感觉不舒服与内置功能乱搞。在这种情况下,无法使用UpValues使其特别不吸引人。谢谢你,LeonidI,我认为这句话是正确的,但一般来说,不建议向Set等重要命令添加downValue,因为这可能会以微妙的方式损坏系统。很清楚。干得好,Leonid(一如既往)@phantomas1234您仍然可以让事情看起来像OOP一样,例如,您可以定义
struct
的方法,使用
UpValues
重新定义
struct
上的
点。我在这篇帖子中给出了一个简单的例子:@belisarius谢谢,尽管这可能比我在这里做的解释更好。如果我能做出更好的解释,我会编辑这篇文章。@belisarius是的,我知道。这正是我现在为一个易于使用的建模框架所做的。工作起来很有魅力。不过,如果能让struct[“ID”]=“NewID”这样的东西也能工作就好了。我想在另一次编辑中添加这段代码,但太懒了,因为它需要另一段解释。我没有从它开始的真正原因是:首先,您可能会通过评估
s
,触发不必要的副作用-而在我的代码中,
s
被分析但未评估。其次,在这种通用代码中,
s
可能不代表L值(可赋值表达式),例如:
struct[stuff]=value
,由此产生的错误消息等可能会让用户感到困惑。@Leonid感谢您的解释。我从他们身上学到了很多。