use*_*407 4 wolfram-mathematica pattern-matching variable-assignment
我想重新定义Subscript
"二叉树坐标"被翻译成"平面阵列坐标":
Unprotect[Subscript];
Subscript[x_, i_, j_] := x[[2 ^ i + j]];
Protect[Subscript];
(* Binomial Tree *)
y = {.1, {.2, .3}} // Flatten;
Subscript[y, 1, 1]
Subscript[y, 1, 1] = .5;
Subscript[y, 1, 1]
Run Code Online (Sandbox Code Playgroud)
我期望得到的是.3, .5
.相反,我得到了,Set::write : Tag Subscript in {.1, .2, .3}_1,1 is Protected
并没有分配价值.请指教.
这是概念上最简单的解决方案 - 您添加一个新的"Up" - 规则来处理分配:
Unprotect[Subscript];
Subscript[x_, i_, j_] := x[[2^i + j]]
Set[Subscript[x_, i_, j_], v_] ^:= x[[2^i + j]] = v;
Protect[Subscript];
(*Binomial Tree*)
y = {.1, {.2, .3}} // Flatten
Subscript[y, 1, 1]
Subscript[y, 1, 1] = .5;
Subscript[y, 1, 1]
Run Code Online (Sandbox Code Playgroud)
您需要一个单独的规则来处理赋值(Set
,=
),否则您在尝试时会尝试分配给Subscript表达式Subscript[y, 1, 1] = .5
虽然上面的解决方案可以按字面意思使用,但它可能不应该使用,因为它重新定义Subscript
了所有类型的第一个参数.这种重新定义可能是不安全的 - 它们可能与其他可能需要的用途发生冲突Subscript
.例如,在某个任意符号x上调用Subscript会导致错误消息,以及我们可能不需要的评估:
In[137]:= Subscript[x, 1, 2]
During evaluation of In[137]:= Part::partd: Part specification x[[4]] is
longer than depth of object. >>
Out[137]= x[[4]]
Run Code Online (Sandbox Code Playgroud)
更安全的替代方法是为要重新定义的二叉树分配一些特殊头(如标记)Subscript
,并使用模式相应地限制这些重定义的范围.以下是它的外观:
Unprotect[btree, Subscript];
ClearAll[btree, Subscript];
Subscript[x_btree, i_, j_] := x[[1, 2^i + j]]
Set[Subscript[x_, i_, j_], v_] ^:= (x[[1, 2^i + j]] = v) /; Head[x] === btree;
Protect[btree, Subscript];
Run Code Online (Sandbox Code Playgroud)
您将btree结构分配给变量,如下所示:
In[156]:= y = btree[{.1, .2, .3}]
Out[156]= btree[{0.1, 0.2, 0.3}]
Run Code Online (Sandbox Code Playgroud)
然后,
In[157]:= Clear[x];
Subscript[y, 1, 1]
Subscript[y, 1, 1] = .5;
Subscript[y, 1, 1]
Subscript[x, 1, 1]
Out[158]= 0.3
Out[160]= 0.5
Out[161]= Subscript[x, 1, 1]
Run Code Online (Sandbox Code Playgroud)
通过这种方式,我们减少了这种重新定义可能对其他一些代码(系统的其余部分)产生的不良影响.
回顾一下涉及的定义Set
,需要注意的一点是我们不能使用像这样的简单模式Set[Subscript[x_btree, i_Integer, j_Integer],v_]:=...
,因为变量(y
这里)Set
在模式匹配时还没有评估到内部的值,所以它不匹配.使用Condition
(/;
)只是一种方法,可以将我们分配的变量,分配出来Set
并进行评估.因此,如果是y
,那么Head[y]
将导致y
评估 - 这是我们实际需要评估表达式的头部的情况.在模式中x_btree
,我们没有x
机会在模式匹配尝试发生之前进行评估,因此模式不匹配(因为它仍然是y
那里的符号).
此处使用的附加规则称为UpValue
.要创建此类规则,需要使用特殊语法(^:=
operator - UpSetDelayed
,是一种创建方法UpValues
).UpValues
是"软"重载函数(包括系统函数)的重要机制,也是自定义数据类型的创建.要了解它们,这里有一个很好的起点 .