如何在MATLAB中生成sentinel值?

如何在MATLAB中生成sentinel值?,matlab,Matlab,以下Python示例可能有助于说明我所说的“哨兵值”的含义: 在上面的代码段中,变量SENTINEL被初始化为一个全新的“nonce”对象,这个对象在定义它的文件之外没有任何内容,也没有任何可以想象的意义foo是一个接受可选参数的函数,opt。常量SENTINEL被foo用于一件事,并且仅用于一件事:测试在没有参数的情况下被调用的条件。如果opt是SENTINEL,则使用完成此操作 要了解为什么需要像SENTINEL这样的廉价“nonce”常量,请将上面的代码片段与使用标准Python值(Non

以下Python示例可能有助于说明我所说的“哨兵值”的含义:

在上面的代码段中,变量
SENTINEL
被初始化为一个全新的“nonce”对象,这个对象在定义它的文件之外没有任何内容,也没有任何可以想象的意义
foo
是一个接受可选参数的函数,
opt
。常量
SENTINEL
foo
用于一件事,并且仅用于一件事:测试在没有参数的情况下被调用的条件。如果opt是SENTINEL,则使用
完成此操作

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

def foo2(opt=None):
    if opt is None:
        opt = make_me_fresh_default_opt_please()
    # etc
此函数
foo2
无法区分以下两个调用1:

总之,这里我所说的“sentinel”是指一个常量值,对于代码的其余部分来说是未知的,它的唯一目的是作为布尔测试的基础

在MATLAB中有没有类似的简单方法来生成这样一个前哨常数

编辑:我想强调的是,我的问题严格来说是关于如何创建一个哨兵,留下了一个关于使用这种哨兵的目的的问题。我提供了一个具体而合理的例子,说明为什么人们可能想要这样一个哨兵常数,部分原因是为了确保这篇文章的读者知道我所说的“哨兵”一词是什么意思。在本例中,sentinel恰好用于测试“未传递参数”的条件,但有无数其他可能的条件需要使用sentinel值进行测试。所以,这个问题,强调地,不是关于测试“没有参数通过”的条件,而是关于生成哨兵常数的问题,一般来说

编辑2:根据Notlikethat和Bas Swinckels的回答:

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
%}
好吧,那可能太可爱了。如果代码与最初的建议更接近,则代码更简单、更清晰(请注意,下面的
make_sentinel
是一个独立的函数):

为了证明
make_sentinel
产生的哨兵确实是独一无二的(而且这种反常行为不会带来好处):


1当然,前面定义的
foo
不能区分
foo()
foo(SENTINEL)
,但是,AFAIC,像后者这样的调用属于“反常编程”的范畴(因为它要求调用代码“走自己的路”来颠覆被调用代码的意图),我不担心这种反常行为。相比之下,前面显示的
foo2(None)
示例说明了在常规编程过程中很容易发生的情况,特别是当它的实际源代码类似于
foo(some_variable)
时,而
一些_变量
无趣地最终持有标准Python值
None

如果您想要一种“简单”的方法来确定函数调用中没有传递任何参数,那么使用
nargin
是惯用的MATLAB方法

在函数体中,调用
nargin
将返回传递给函数的参数数。所以你可以像这样写代码

function foo(a, b)
    switch nargin
        case 0
            % Handle the no-argument case...
        case 1
            % Handle the one-argument case...
        otherwise
            % All arguments supplied...
    end
    % Other code here...
end

有关详细信息,请参阅。

如果您确实希望具有唯一的sentinel值,可以创建自己的sentinel类。但我想,在任何现实环境中,找到任何函数或用户输入都无法生成的标准数字/单元格/结构/字符串都应该是微不足道的。这可以简单到

SENTINEL  = 'qqqxyz_lalala_the_user_would_be_a_moron_to_use_this_string';
使用此值的用户显然属于您对“反常编程”的定义。使用此函数可以测试变量是否为sentinel:

% 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
issentinel = @(var) ischar(var) && strcmp(var, SENTINEL)

另请注意该类,它允许您为缺少的参数定义默认值,这可能会减少对sentinel值的需要。

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

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

为了更简单而牺牲保证的唯一性,
tempname
是一种生成字符串的简单方法,它不太可能与有效数据发生冲突(特别是如果有效数据不是字符串…

不,我的问题正是我问的:我正在寻找一种在MATLAB中生成哨兵的方法。为了澄清,你不是在寻找默认值行为,你是在寻找一个哨兵,它将被用于完全不同的目的?@BenVoigt:我在我的帖子中添加了一个编辑,希望能澄清我的目的。好吧,你没有一个哨兵值可以用于什么的“具体和合理的例子”,因为MATLAB不允许默认值的参数,只允许可选的参数。若要检测缺少的参数,必须使用
nargin
,哨兵值在具体情况下不起作用。@BenVoigt:除了
nargin
之外,还有其他方法检测缺少的参数。关于
inputParser
@BenVoigt,请参见文档:此外,我的“具体而合理的示例”是用Python编写的(我对Python的熟悉程度是MATLAB的1000倍),而且在该语言中它确实是具体而合理的。这个例子的目的是澄清我所说的“sentinel”一词的含义,而不是对MATLAB做一个陈述。+1只是针对提议的sentinel,即使它有点…-比如说-非传统。另外,尽管我对
inputParser
没有太多经验,但如果我正确理解它的文档,然后,只有在可以提前指定真正的默认值的情况下,您关于它的声明才有效,但情况并非总是如此。如果用户未提供值,则可能需要动态确定要使用的值(即“在运行时”),例如,通过从远程源获取该值,等等。在这种情况下,为
inputParser
提供的所谓“默认值”将
SENTINEL  = 'qqqxyz_lalala_the_user_would_be_a_moron_to_use_this_string';
issentinel = @(var) ischar(var) && strcmp(var, SENTINEL)
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
SENTINEL = java.lang.Object;
% etc...