设置“结构"在 Mathematica 中安全地 [英] Setting up a "struct" in Mathematica safely

查看:26
本文介绍了设置“结构"在 Mathematica 中安全地的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

像在 Mathematica 中那样做记录的问题已经在几个地方讨论过,比如 StructMathematica 中的数据类型?.

The question on making a record like in Mathematica has been discussed in few places, such as Struct data type in Mathematica?.

所有这些方法的问题在于,人们似乎失去了执行对每个参数进行特定的额外检查,例如 x_?NumericQ.

The problem with all these methods, is that one loses the ability, it seems, to do the specific extra check on each argument, as in when one does x_?NumericQ.

我的问题是:有没有办法在 Mathematica 中创建一个记录或一个结构体,并且能够对单个元素使用上述检查?

My question is: Is there a way in Mathematica to make a record or a struct, and yet be able to use the checking as above on the individual elements?

我正在尝试使用一种方法,因为我厌倦了使用 10 个参数调用函数(有时无法避免这种情况),即使我尝试使每个函数都非常具体,以最小化参数的数量,有些函数只需要很多参数就可以完成特定的工作.

I am trying to settle down on one method to use as I am tired of having functions called with 10 parameters on them (sometimes one can't avoid this), even when I try to make each function very specific, to minimze the number of parameters, some functions just need many parameters to do the specific job.

首先展示我所知道的三种方法.

First I show the three methods I know about.

foo[p_]:=Module[{},
    Plot[Sin[x],{x,from/.p,to/.p}]
]
p={from->-Pi,to->Pi};
foo[p]

优点:安全,就像我将符号从"更改为其他符号一样,它仍然可以工作.如下例.

Advantage: safe, as if I change the symbol 'from' to something else, it will still work. As the following example.

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]

方法二

Clear[p,foo];
foo[p_]:=Module[{},
    Print[p];
    Plot[Sin[x],{x,p["from"],p["to"]}]
]
p["from"] = -Pi;
p["to"]   = Pi;

foo[p]

优点:同样安全,字符串是不可变的.不必担心from"值的变化.但是到处都有字符串是不是太可读了?

Advantage: also safe, strings are immutable. Do not have to worry about the "from" value changing. But having strings everywhere is not too readable?

Clear[p,to,from];
foo[p_]:=Module[{},
    Plot[Sin[x],{x,p[from],p[to]}]
]
p[from] = -Pi;
p[to]   = Pi;

foo[p]

缺点:如果任何符号from"或to"在某处被覆盖,都会导致问题,如

Disadvantage: if any of the symbols 'from' or 'to' get overwritten somewhere, will cause problem, as in

from=-4; (*accidentally the symbol from is assigned a value*)
foo[p]   

所以.我认为方法(1)是最安全的.但现在我失去了这样做的能力:

So. I think method (1) is the most safe. But now I lose the ability to do this:

foo[from_?NumericQ, to_?NumericQ] := Module[{},
    Plot[Sin[x], {x, from, to}]
]
from = -Pi; to = Pi;
foo[from, to]

所以,我希望得到一个想法,能够结合制作记录"之类的,但同时,仍然能够对记录中的各个元素使用参数检查?或者这个问题对基于 Mathematica 函数/规则的编程风格来说不是很好?

So, I am hoping to get an idea to be able to combine making a 'record' like, but at the same time, still be able to use the parameter checking on individual elements in the record? Or is this question is not not well posed for Mathematica functional/rule based programming style?

这是我希望 Mathematica 拥有的一件事,它是帮助管理和组织程序中使用的所有变量的真实记录.

That is one thing I wish Mathematica had, which is a real record to help manage and organize all the variables used in the program.

推荐答案

首先,我想提一下,您列出的所有方法都存在 IMO 缺陷和危险.我不喜欢它们的主要原因是它们引入了对全局变量的隐式依赖(讨论了为什么不好的原因,例如 此处),并且还可能弄乱范围.它们的另一个问题是这些方法看起来不能很好地扩展到同时存在的结构的许多实例.你列出的第二种方法看起来最安全,但它也有它的问题(字符串作为字段名,无法对这样的结构进行类型检查,那里使用的符号也可能不小心有值).

First, I'd like to mention that all the methods you listed are IMO flawed and dangerous. The main reason why I don't like them is that they introduce implicit dependences on global variables (the reasons why this is bad are discussed e.g. here), and can also mess up with the scoping. Another problem of them is that those approaches look like they won't scale nicely to many instances of your structs existing simultaneously. The second method you listed seems the safest, but it has its problems as well (strings as field names, no way to type-check such a struct, also symbols used there may accidentally have a value).

在我的帖子这里中,我讨论了一种可能的构建方式可变数据结构,其中方法可以进行额外检查.我将在此处复制相关部分:

In my post here I discussed a possible way to build mutable data structures where methods can do extra checks. I will copy the relevant piece here:

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]; 

请注意,我在构造函数和 setter 中添加了检查,以说明如何做到这一点.有关如何使用以这种方式构建的结构的更多详细信息,您可以在我提到的帖子和那里找到的进一步链接中找到.

Note that I added checks in the constructor and in the setters, to illustrate how this can be done. More details on how to use the structs constructed this way you can find in the mentioned post of mine and further links found there.

您的示例现在将显示为:

Your example would now read:

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]

请注意,这种方法的主要优点是正确封装了状态,隐藏了实现细节,并且范围界定没有危险.

Note that the primary advantages of this approach are that state is properly encapsulated, implementation details are hidden, and scoping is not put in danger.

这篇关于设置“结构"在 Mathematica 中安全地的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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