Nas*_*ser 5 wolfram-mathematica
关于在Mathematica中创建记录的问题已在少数几个地方讨论过,例如Mathematica中的Struct数据类型?.
所有这些方法的问题在于,人们似乎失去了对每个参数进行特定额外检查的能力,就像人们做的那样x_?NumericQ
.
我的问题是:在Mathematica中有没有办法制作记录或结构,但是能够在各个元素上使用上述检查?
我试图找到一种方法来使用,因为我厌倦了在它们上面调用10个参数的函数(有时候一个人无法避免这种情况),即使我试图使每个函数都非常具体,最小化数量参数,一些功能只需要很多参数来完成特定的工作.
首先,我展示了我所知道的三种方法.
foo[p_]:=Module[{},
Plot[Sin[x],{x,from/.p,to/.p}]
]
p={from->-Pi,to->Pi};
foo[p]
Run Code Online (Sandbox Code Playgroud)
优点:安全,好像我将符号'从'更改为其他东西,它仍然有效.如下例所示.
foo[p_]:=Module[{},
Plot[Sin[x],{x,from/.p,to/.p}]
]
p={from->-Pi,to->Pi};
from=-1; (* By accident the symbol from was set somewhere. It will work*)
foo[p]
Run Code Online (Sandbox Code Playgroud)
Clear[p,foo];
foo[p_]:=Module[{},
Print[p];
Plot[Sin[x],{x,p["from"],p["to"]}]
]
p["from"] = -Pi;
p["to"] = Pi;
foo[p]
Run Code Online (Sandbox Code Playgroud)
优点:也是安全的,字符串是不可变的.不必担心"从"值的变化.但到处都有字符串不太可读?
Clear[p,to,from];
foo[p_]:=Module[{},
Plot[Sin[x],{x,p[from],p[to]}]
]
p[from] = -Pi;
p[to] = Pi;
foo[p]
Run Code Online (Sandbox Code Playgroud)
缺点:如果任何符号'从'或'到'某处被覆盖,将导致问题,如
from=-4; (*accidentally the symbol from is assigned a value*)
foo[p]
Run Code Online (Sandbox Code Playgroud)
所以.我认为方法(1)是最安全的.但现在我失去了这样做的能力:
foo[from_?NumericQ, to_?NumericQ] := Module[{},
Plot[Sin[x], {x, from, to}]
]
from = -Pi; to = Pi;
foo[from, to]
Run Code Online (Sandbox Code Playgroud)
所以,我希望有一个想法能够组合制作一个'记录',但同时,仍然可以使用参数检查记录中的各个元素?或者这个问题对于基于Mathematica功能/规则的编程风格是不是很好?
这是我希望Mathematica拥有的一件事,这是一个真正的记录,可以帮助管理和组织程序中使用的所有变量.
Leo*_*rin 10
首先,我想提一下,你列出的所有方法都是IMO有缺陷和危险的.我不喜欢它们的主要原因是它们引入了对全局变量的隐式依赖(这里讨论的原因很糟糕,例如这里讨论),并且还可能搞乱范围.它们的另一个问题是,这些方法看起来不会很好地适应同时存在的结构的许多实例.你列出的第二种方法似乎是最安全的,但它也有它的问题(字符串作为字段名,没有办法输入检查这样的结构,也可能意外地使用了符号值).
在我的帖子中,我讨论了构建可变数据结构的可能方法,其中方法可以进行额外的检查.我将在这里复制相关文章:
Unprotect[pair, setFirst, getFirst, setSecond, getSecond, new, delete];
ClearAll[pair, setFirst, getFirst, setSecond, getSecond, new, delete];
Module[{first, second},
first[_] := {};
second[_] := {};
pair /: new[pair[]] := pair[Unique[]];
pair /: new[pair[],fst_?NumericQ,sec_?NumericQ]:=
With[{p=new[pair[]]},
p.setFirst[fst];
p.setSecond[sec];
p];
pair /: pair[tag_].delete[] := (first[tag] =.; second[tag] =.);
pair /: pair[tag_].setFirst[value_?NumericQ] := first[tag] = value;
pair /: pair[tag_].getFirst[] := first[tag];
pair /: pair[tag_].setSecond[value_?NumericQ] := second[tag] = value;
pair /: pair[tag_].getSecond[] := second[tag];
];
Protect[pair, setFirst, getFirst, setSecond, getSecond, new, delete];
Run Code Online (Sandbox Code Playgroud)
请注意,我在构造函数和setter中添加了检查,以说明如何完成此操作.有关如何使用这种方式构造的结构的更多细节,您可以在我提到的帖子中找到并在那里找到更多链接.
你的例子现在是:
foo[from_?NumericQ, to_?NumericQ] :=
Module[{}, Plot[Sin[x], {x, from, to}]];
foo[p_pair] := foo[p.getFirst[], p.getSecond[]]
pp = new[pair[], -Pi, Pi];
foo[pp]
Run Code Online (Sandbox Code Playgroud)
请注意,此方法的主要优点是状态被正确封装,实现细节被隐藏,并且范围不会处于危险之中.