如何在MATLAB中设定哨兵值? [英] How to make a sentinel value in MATLAB?

查看:147
本文介绍了如何在MATLAB中设定哨兵值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的示例在Python中可能有助于说明警戒值"的含义:

The following example, in Python, may help illustrate what I mean by a "sentinel value":

SENTINEL = object()
def foo(opt=SENTINEL):
    if opt is SENTINEL:
        opt = make_me_fresh_default_opt_please()
    # etc

在变量SENTINEL上方的代码段中,初始化为一个全新的"nonce"对象,该对象实际上没有任何内容,并且在定义该文件的文件之外的其他任何地方都没有可能的含义. foo是一个带有可选参数opt的函数.常量SENTINELfoo用于一件事和仅一件事:测试无参数调用的条件.这是通过if opt is SENTINEL完成的.

In the snippet above the variable SENTINEL is initialized to a brand new "nonce" object, one that has, as it were, no content, and no conceivable meaning anywhere else outside the file where it is defined. foo is a function that takes an optional argument, opt. The constant SENTINEL is used by foo for one thing and one thing only: to test the condition of being called with no arguments. This is done with if opt is SENTINEL.

要了解为什么要使用像SENTINEL这样的廉价"nonce"常量,请将上面的代码段与使用标准Python值(None)来测试无参数条件的内容进行对比:

To see why one would want such a cheap, "nonce" constant like SENTINEL, contrast the snippet above with one that uses a standard Python value (None) to test the no-argument condition:

def foo2(opt=None):
    if opt is None:
        opt = make_me_fresh_default_opt_please()
    # etc

此函数foo2不能区分下面的两个调用 1 :

This function foo2 cannot distinguish between the two calls below1:

foo2()
foo2(None)

因此,总而言之,这里的前哨"是指其余代码未知的常量值,其唯一目的是用作某种条件下布尔测试的基础.

So, in sum, by "sentinel" here I mean a constant value that is unknown to the rest of the code, and whose only purpose is to serve as the basis for a boolean test for some condition.

在MATLAB中是否有类似的简单方法来生成这样的定点常量?

Is there a similarly simple way to generate such a sentinel constant in MATLAB?

我想强调一点,我的问题严格来说是关于如何创建一个哨兵的问题,而未提及使用此类哨兵的目的的问题.我提供了一个具体而合理的示例,说明为什么有人想要这样一个定点常量,部分目的是确保该帖子的读者知道我所说的哨兵"一词的含义.在此示例中,前哨恰好发生用于测试无参数传递"条件,但是还有许多其他可能的条件需要使用前哨值进行测试.因此,这个问题着重不是测试无参数传递"条件,而是一般而言,生成哨兵常量的问题.

I want to stress that my question is strictly about how to create a sentinel, leaving open the issue of the purpose to which such sentinel would be used. I provided a concrete and plausible example of why one may want such a sentinel constant, in part to make sure that readers of the post would know what I meant by the word "sentinel". In this example, the sentinel just happens to be used to test for a "no argument passed" condition, but there are countless other possible conditions that one may want to test using a sentinel value. So, this question is, emphatically, not about testing for a "no argument passed" condition, but about the problem of generating sentinel constants, in general.

基于Notlikethat's和Bas Swinckels的答案:

based on Notlikethat's and Bas Swinckels's answers:

function y = foo(varargin)
    p = inputParser;
    p.addParameter('Opt', @DEFAULT);
    p.parse(varargin{:});

    opt = p.Results.Opt;
    if DEFAULT(opt)
        opt = rand();
    end

    y = opt;
    % etc
end

function its_me = DEFAULT(opt)
    its_me = isequal(opt, @DEFAULT);
end

%{
>> foo('Opt', 3)
ans =
     3
>> foo()
ans =
    0.9134
>> foo
ans =
    0.6324
%}

好的,那可能太可爱了.如果代码更接近Notlikethat的原始建议(请注意,下面的make_sentinel是一个独立的函数),则该代码既简单又清晰:

OK, that's maybe too-cute-by-half. The code is both simpler and clearer if it stays closer to Notlikethat's original suggestion (note that make_sentinel below is a free-standing function):

% foo.m
function y = foo(varargin)
    DEFAULT = make_sentinel();
    p = inputParser;
    p.addParameter('Opt', DEFAULT);
    p.parse(varargin{:});

    opt = p.Results.Opt;
    if isequal(opt, DEFAULT)
        opt = rand();
    end

    y = opt;
    % etc
end

% make_sentinel.m
function sentinel = make_sentinel()
    sentinel = ...
       @() 'qqqxyz_lalala_the_user_would_be_a_moron_to_use_this_function';
    % or, more conventionally,
    % sentinel = @() 0;
end


>> foo('Opt', 6)
ans =
     6
>> foo()
ans =
    0.9575
>> foo
ans =
    0.9649

并且要证明make_sentinel产生的哨兵确实是独一无二的(而且反常不会付出代价):

And to show that the sentinels produced by make_sentinel are indeed unique (and that perversity won't pay):

>> foo('Opt', make_sentinel())
ans = 
    @()'qqqxyz_lalala_the_user_would_be_a_moron_to_use_this_function'


1 当然,前面定义的foo不能区分foo()foo(SENTINEL),但是,AFAIC,像后者一样的调用属于不正当"类别.编程"(因为它要求调用代码摆脱干扰"以颠覆被调用代码的意图),而且我不必担心这种麻烦.相反,前面显示的foo2(None)示例说明了在例行编程过程中很容易发生的情况,尤其是当它的实际源代码类似于foo(some_variable)some_variable意外地持有标准Python时值None.


1 Of course, the foo defined earlier cannot distinguish between foo() and foo(SENTINEL), but, AFAIC, a call like the latter falls within the category of "perverse programming" (since it requires the calling code to "go out of its way" to subvert the called code's intentions), and I don't worry about such perversities. In contrast, the foo2(None) example shown earlier illustrates a situation that could happen easily in the course of routine programming, especially when the actual source code for it is something like foo(some_variable), and some_variable unintendedly ends up holding the standard Python value None.

推荐答案

一个解决方案几乎是直接等效的:

One solution would be pretty much the direct equivalent:

function y = foo(opt)
    %default argument
    if nargin<1
        opt = @SENTINEL;
    end

    %actual check
    if isequal(opt, @SENTINEL)
        opt = make_me_fresh_default_opt_please()
    end

    % etc
end

function SENTINEL  % private function in the same file
end

当然不是那么简单,但这和其他任何东西一样,都取决于Matlab语法.

Admittedly not quite as simple, but that's as much down to Matlab syntax as anything else.

您可能还可以作弊,并以完全相同的方式基于 :

You could probably also cheat a bit and base it on exactly the same approach:

SENTINEL = java.lang.Object;
% etc...

为了更简单起见,牺牲保证的唯一性,tempname是生成不太可能与有效数据发生冲突的字符串的一种简便方法(尤其是如果有效数据不是字符串的情况下...)

Sacrificing guaranteed uniqueness for even more simplicity, tempname is an easy way to generate a string that's unlikely to collide with valid data (especially if valid data isn't strings...)

这篇关于如何在MATLAB中设定哨兵值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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