函数句柄内的逻辑短路
Logical short-circuit inside a function handle
我有一个对任意大小的二维数组进行操作的函数句柄:
R2T = @(DL1,DL2) arrayfun(@(DL1,DL2)...
1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-...
DL1./DL2,[minLim maxLim])) ...
,DL1,DL2) - C1;
以下是其功能的自下而上的细分:
fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,[minLim maxLim])
- 该位在区间 [minLim maxLim]
上查找所考虑函数的零,其中 fFitObj1
和 fFitObj2
是之前可用的函数句柄,C1
是一些已知常数,并提供了 DL1, DL2
。
@(DL1,DL2)1/(fzero(...))
- fzero
的包装器,允许从外部提供 DL1
和 DL2
。
arrayfun(@(DL1,DL2)...,DL1,DL2)
- 另一个包装器,当 DL1, DL2
作为矩阵提供时,它允许 fzero
正确地逐个元素地操作。
R2T = @(DL1,DL2) arrayfun(...) - C1;
- 另一个允许从外部提供 DL1, DL2
的包装器。
我的问题是有时矩阵 DL1, DL2
可能包含 NaN
个值,在这种情况下 fzero
return 出现以下错误:
Error using fzero (line 242)
Function values at interval endpoints must be finite and real.
这就是为什么我很自然地想到可用的 operations with short-circuiting,所以我尝试将 any(isnan([DL1,DL2]))
合并到其中,这样 fzero
甚至不会被评估,如果它的输入会是 NaN
- 但无论我尝试什么(例如定制的三元运算符), fzero
似乎都被评估并且代码错误。
期望的结果: 我想实现 fzero
的惰性评估,仅在输入有效时发生(在这种情况下,不是 NaN
) 和 return NaN
否则如下面的 Edit 所示。
相关资源:
编辑:
这是一段说明问题的代码 (MATLAB 2014a):
clear variables; clc;
LIM = [0 5];
fFitObj1 = @(x)x.^2; fFitObj2 = @(x)1;
C1 = 100;
[DL1A,DL2A,DL1B] = deal(ones(2));
DL1B(4) = NaN; DL2B = DL1B;
R2T = @(DL1,DL2) arrayfun(@(DL1,DL2)...
1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-...
DL1./DL2,LIM)) ...
,DL1,DL2) - C1;
R2T(DL1A,DL2A) %//case A, runs fine
%{
// ans =
//
// -99 -99
// -99 -99
%}
R2T(DL1B,DL2B) %//case B, errors due to NaN
%{
// Error using fzero (line 242)
// Function values at interval endpoints must be finite and real.
//
// Error in @(DL1,DL2)1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,LIM))
//
//
// Error in @(DL1,DL2)arrayfun(@(DL1,DL2)1/(fzero( .....
%}
在案例 B 中,期望的结果是:
ans =
-99 -99
-99 NaN
如前所述:这样做内联是疯狂,你最好使用一个单独的函数/.m
文件。
会是
- 更快
- 更容易阅读
- 更容易写
- 更容易调试
例如,您可以采用与此类似的方式执行此操作:
function out = R2TComputation(DL1, DL2, minLim, maxLim, C1)
...%Compute whatever R2T would compute.
要获得与原始匿名函数相同的接口,您只需创建
R2T = @(DL1, DL2) R2TComputation(DL1, DL2, minLim, maxLim, C1)
这将在您创建此句柄时捕获 minLim
、maxLim
和 C1
的当前值 R2T
。
另一种选择是使用 nested function 而不是外部的。它可以访问父函数的变量,但仍然可以使用 if
、else
和您需要的所有其他基本工具。唯一的缺点:不能从其他文件中访问它。
... % Main function stuff
function out = R2T(DL1, DL2)
if ...
out = ...
...
end
... % Use R2T ...
不过,为了搬起石头砸自己的脚,这里是if-else
的内联版本,我本着Loren's blog post和的精神写的不建议使用 ,因为使用单个表达式而不是相应的 if
-else
语句几乎没有任何好处。
ifelse = @(cond, varargin) varargin{1+~cond}(); %Only for the insane
如果你想让它用零参数做lazy evaluation, you need to pass an anonymous function,然后ifelse
会计算(这就是ifelse
中最后两个括号()
的用途) :
ifelse(true, 42, @()disp('OMG! WTF! THIS IS CRAZY!!111'))
如果您只是将对 disp
的函数调用编写为 ifelse
的参数而没有 @()
,则该函数甚至会在我们访问 ifelse
之前被调用。这是因为 MATLAB(与大多数其他语言一样)首先计算函数的 return 值,然后将其作为参数传递给 ifelse
。
在您的情况下,结果代码将是:
R2T = @(DL1,DL2) arrayfun(@(DL1,DL2)...
ifelse(~any(isnan([DL1, DL2])), ...
@() 1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,LIM)), ...
NaN), ...
DL1, DL2) - C1;
我有一个对任意大小的二维数组进行操作的函数句柄:
R2T = @(DL1,DL2) arrayfun(@(DL1,DL2)...
1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-...
DL1./DL2,[minLim maxLim])) ...
,DL1,DL2) - C1;
以下是其功能的自下而上的细分:
fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,[minLim maxLim])
- 该位在区间[minLim maxLim]
上查找所考虑函数的零,其中fFitObj1
和fFitObj2
是之前可用的函数句柄,C1
是一些已知常数,并提供了DL1, DL2
。@(DL1,DL2)1/(fzero(...))
-fzero
的包装器,允许从外部提供DL1
和DL2
。arrayfun(@(DL1,DL2)...,DL1,DL2)
- 另一个包装器,当DL1, DL2
作为矩阵提供时,它允许fzero
正确地逐个元素地操作。R2T = @(DL1,DL2) arrayfun(...) - C1;
- 另一个允许从外部提供DL1, DL2
的包装器。
我的问题是有时矩阵 DL1, DL2
可能包含 NaN
个值,在这种情况下 fzero
return 出现以下错误:
Error using fzero (line 242)
Function values at interval endpoints must be finite and real.
这就是为什么我很自然地想到可用的 operations with short-circuiting,所以我尝试将 any(isnan([DL1,DL2]))
合并到其中,这样 fzero
甚至不会被评估,如果它的输入会是 NaN
- 但无论我尝试什么(例如定制的三元运算符), fzero
似乎都被评估并且代码错误。
期望的结果: 我想实现 fzero
的惰性评估,仅在输入有效时发生(在这种情况下,不是 NaN
) 和 return NaN
否则如下面的 Edit 所示。
相关资源:
编辑:
这是一段说明问题的代码 (MATLAB 2014a):
clear variables; clc;
LIM = [0 5];
fFitObj1 = @(x)x.^2; fFitObj2 = @(x)1;
C1 = 100;
[DL1A,DL2A,DL1B] = deal(ones(2));
DL1B(4) = NaN; DL2B = DL1B;
R2T = @(DL1,DL2) arrayfun(@(DL1,DL2)...
1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-...
DL1./DL2,LIM)) ...
,DL1,DL2) - C1;
R2T(DL1A,DL2A) %//case A, runs fine
%{
// ans =
//
// -99 -99
// -99 -99
%}
R2T(DL1B,DL2B) %//case B, errors due to NaN
%{
// Error using fzero (line 242)
// Function values at interval endpoints must be finite and real.
//
// Error in @(DL1,DL2)1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,LIM))
//
//
// Error in @(DL1,DL2)arrayfun(@(DL1,DL2)1/(fzero( .....
%}
在案例 B 中,期望的结果是:
ans =
-99 -99
-99 NaN
如前所述.m
文件。
会是
- 更快
- 更容易阅读
- 更容易写
- 更容易调试
例如,您可以采用与此类似的方式执行此操作:
function out = R2TComputation(DL1, DL2, minLim, maxLim, C1)
...%Compute whatever R2T would compute.
要获得与原始匿名函数相同的接口,您只需创建
R2T = @(DL1, DL2) R2TComputation(DL1, DL2, minLim, maxLim, C1)
这将在您创建此句柄时捕获 minLim
、maxLim
和 C1
的当前值 R2T
。
另一种选择是使用 nested function 而不是外部的。它可以访问父函数的变量,但仍然可以使用 if
、else
和您需要的所有其他基本工具。唯一的缺点:不能从其他文件中访问它。
... % Main function stuff
function out = R2T(DL1, DL2)
if ...
out = ...
...
end
... % Use R2T ...
不过,为了搬起石头砸自己的脚,这里是if-else
的内联版本,我本着Loren's blog post和的精神写的不建议使用 ,因为使用单个表达式而不是相应的 if
-else
语句几乎没有任何好处。
ifelse = @(cond, varargin) varargin{1+~cond}(); %Only for the insane
如果你想让它用零参数做lazy evaluation, you need to pass an anonymous function,然后ifelse
会计算(这就是ifelse
中最后两个括号()
的用途) :
ifelse(true, 42, @()disp('OMG! WTF! THIS IS CRAZY!!111'))
如果您只是将对 disp
的函数调用编写为 ifelse
的参数而没有 @()
,则该函数甚至会在我们访问 ifelse
之前被调用。这是因为 MATLAB(与大多数其他语言一样)首先计算函数的 return 值,然后将其作为参数传递给 ifelse
。
在您的情况下,结果代码将是:
R2T = @(DL1,DL2) arrayfun(@(DL1,DL2)...
ifelse(~any(isnan([DL1, DL2])), ...
@() 1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,LIM)), ...
NaN), ...
DL1, DL2) - C1;