重载 Set[a, b] (a = b) [英] Overloading Set[a, b] (a = b)

查看:36
本文介绍了重载 Set[a, b] (a = b)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想重载 Mathematica 的 Set 函数 (=),这对我来说太棘手了(参见下面的代码示例).我成功重载了其他函数(例如代码示例中的 Reverse).有什么建议吗?

I would like to overload Mathematica's Set function (=), which turns out to be too tricky for me (see following code example). I successfully overloaded other functions (e.g. Reverse in the code example). Any suggestions?

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 值),并且它们的部分不能赋值.我相信这段代码会做一些类似于你想要的事情:

I don't think that what you want can be done with UpValues (alas), since the symbol (tag) must be not deeper than level one for definition to work. Also, the semantics you want is somewhat unusual in Mathematica, since most Mathematica expressions are immutable (not L-values), and their parts can not be assigned values. I believe that this code will do something similar to what you want:

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 之类的重要命令中,因为这可能会以微妙的方式破坏系统.

But generally, adding DownValues to such important commands as Set is not recommended since this may corrupt the system in subtle ways.

编辑

扩展一下您的尝试失败的原因:Mathematica 使用参数保持机制(Hold* - 属性,描述了 此处).这种机制尤其允许它模仿赋值所需的按引用传递语义.但是,在您分配给 var1 的那一刻,Set 已经不知道 var1 中存储了什么,因为它只有符号var1,而不是它的值.模式_struct 不匹配,因为即使变量已经存储了一些structSet 也只有变量名.为了匹配成功,Set 中的变量必须计算其值.但是,该值是不可变的,您无法分配给它.我建议的代码测试变量是否具有 struct[something] 形式的赋值,如果是,则修改第一部分(Part 命令是一个例外,它可以修改 L 值表达式的部分,前提是这些部分已经存在).

Expanding a bit on why your attempt failed: Mathematica implements flow control and assignment operators using the mechanism of argument holding (Hold* - attributes, described here). This mechanism allows it to, in particular, imitate pass-by-reference semantics needed for assignments. But then, at the moment when you assign to var1, Set does not know what is stored in var1 already, since it only has the symbol var1, not its value. The pattern _struct does not match because, even if the variable already stores some struct, Set only has the variable name. For the match to be successful, the variable inside Set would have to evaluate to its value. But then, the value is immutable and you can not assign to it. The code I suggested tests whether the variable has an assigned value that is of the form struct[something], and if so, modifies the first part (the Part command is an exception, it can modify parts of an L-value expression provided that those parts already exist).

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

You can read more on the topics of Hold* - attributes and related issues in many places, for example here and here

这篇关于重载 Set[a, b] (a = b)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆