如何在Matlab中嵌套匿名函数?

时间:2013-06-07 01:05:16

标签: matlab nested anonymous-function

我有一个存储匿名函数的文件funcs.m。它们必须可以被目录中的文件使用。目前,我使用匿名函数,以便在不同的文件中执行文件funcs.m,但我认为这是一种错误的处理方式。其他函数如main.m及其嵌套函数nest.m需要使用funcs.m中的匿名函数。我认为路径不会解决这个问题,因为文件在同一个文件夹中。基本上我可以通过将匿名函数复制粘贴到每个文件来解决这个问题,但代码闻起来如此:

有没有办法在Matlab中重用具有anon函数的funcs.m?

示例

  

的main.m

function main
funcs; % loads the anonymous functions
nest(par1,...,parN)
end
     

nest.m

function nest(par1,...,parN)
funcs; %ERRR: This fires err, why? Look: this was sourced already in main.m!
function neededOnlyHere(par100)
    bq(q,A) %This needs the functions of the funcs
end

neededOnlyHere(somePar) %ERR to use the anon funcs from funcs
end
     

函数main.m和nest.m使用此函数funcs.m具有匿名函数

bq=@(q,A) q*A;                              %Bolded q
I=@(ii,jj,A) find(A(ii,:)==1 & A(jj,:)==0); 
AiNotj=zeros(1,Ncut);                       
...
     

错误

Attempt to add "bq" to a static workspace.
 See MATLAB Programming, Restrictions on
 Assigning to Variables for details.

Error in funcs (line 10)
bq=@(q,A) q*A;
%Bolded q

2 个答案:

答案 0 :(得分:6)

为什么会破坏

nest.m中调用它时会出现错误,因为具有嵌套函数会使其封闭函数的工作空间成为“静态工作空间”;也就是说,无法通过eval()assignin()或其他“动态”技术添加变量名称;只允许在该函数文本中显式指定的变量。评估脚本以定义局部变量 - 这是您在调用funcs.m时所做的 - 是“动态的”,因此在具有嵌套函数的函数中禁止。它适用于main.m因为main没有嵌套函数,因此是一个“动态”工作区。

有几种方法可以更改它以使用静态工作区和嵌套函数。首先要问的是你是否真的需要让它们成为匿名函数?

改为使用包函数

如果您不需要它们本身就是匿名函数,只需将它们分解并将每个函数作为常规函数放在它自己的.m文件中;例如bg.mI.mAiNotj.m等。然后它们全部可用于该目录中的所有其他功能。

如果它变成了乱七八糟的文件,或者你想要限制它们并且可能只使它们可用于真正需要它们的所选函数(即当前调用funcs()的函数),那么你可以将它们粘在一个包装里。创建一个名为+myfuncs的子目录,并移动所有小函数文件;例如+myfuncs/bq.m+myfuncs/I.m+myfuncs/AiNotj.m。 (+前缀告诉Matlab目录是一个包。)然后你可以通过import myfuncs.*直接替换你当前正在调用的地方{{1 }}

funcs()

您可以从命令行执行function nest(par1,...,parN) import myfuncs.*; function neededOnlyHere(par100) bq(q,A) % This will work, resolving to myfuncs.bq end ,以便以交互方式使用它们。

这可能就是Matlab本身希望你组织这样的相关功能集群,这将是我的第一个方法。这是最不“臭”恕我直言。如果你真的希望能够在import myfuncs.*这样的单个文件中编辑它们,为了方便起见,你可以在Perl或者解析funcs.m的任何东西中编写一个小代码,并将它们作为等效的单独函数输出。预处理步骤。 (我认为你不能在像这样的M文件中定义多个顶级函数,但是很好。)

如果你真的需要使用匿名函数,那么有一些解决方法。

在结构中传递函数

您可以使用字段名称而不是本地变量名称来更改funcs()函数以实际返回所有这些匿名函数的结构。

funcs.m

为此,你必须在所有函数引用前加上你持有它们的结构名称。不知道这对你来说有多大。

function out = funcs
out.bq=@(q,A) q*A;                              %Bolded q
out.I=@(ii,jj,A) find(A(ii,:)==1 & A(jj,:)==0); 
out.AiNotj=zeros(1,Ncut);                       

预分配变量

要使funcs()按原样运行,您可以静态地预分配具有您将要使用的所有函数名的变量,因此Matlab解析器将它们识别为静态分配的变量。然后,当您调用funcs()时,它将重新分配现有变量的值,这在动态工作空间中是允许的。

function nest(par1,...,parN)
fs = funcs;
function neededOnlyHere(par100)
    fs.bq(q,A) %This needs the functions of the funcs
end

这会有点痛苦,因为每当添加新的函数名时,您都必须重新编辑每个使用func的文件。您至少可以通过解析function nest(par1,...,parN) [bq, I, AiNotj] = deal(); % Preallocate all names from funcs funcs; function neededOnlyHere(par100) bq(q,A) %This needs the functions of the funcs end 并输出“[bg,I,AiNotj,...] = deal();”来编写一个perl脚本来自动生成该行代码。使用它找到的所有功能,您只需将其复制到您的代码中即可。

另一种方法是让func实际返回其输出列表中的所有函数。只要您不删除或更改现有匿名函数的顺序,即使在向funcs.m添加新函数时,这也可以继续工作。

funcs.m

答案 1 :(得分:1)

传递匿名函数的方法有很多种:

1)传递函数本身:

function main
f = @(t) t^2 - 3;
param = randn(12,1);
g = test22(param,f);
disp (g)
end

function g = test22(param,f)
g = f(param(2));
disp(param(2))
end

2)使用全局变量(通常应该在复杂的代码中避免使用)

function main
global f
f = @(t) t^2 - 3;
param = randn(12,1);
g = test22(param);
disp (g)
end

function g = test22(param)    
global f
g = f(param(2));
disp(param(2))
end