简体   繁体   English

递归匿名函数Matlab

[英]Recursive Anonymous Function Matlab

I know that this is not what anonymous functions are made for, but just as a puzzle I tried to make a recursive function via anonymous functions. 我知道这不是匿名函数的用途,但就像我试图通过匿名函数创建递归函数一样。 The prototype of recursive functions obviously is the factorial function. 递归函数的原型显然是阶乘函数。 The problem is that it is difficult to make a case distinction within the anonymous functions. 问题是,它是很难使匿名函数的情况区分。 What I managed to do so far is following: 到目前为止我设法做的是:

f=@(cn,n,f)eval('if n>1; f(cn*n,n-1,f);else;ans=cn;end');
f=@(n)f(1,n,f);

Or alternatively: 或者:

f=@(cn,n,f)eval('if n>1; f(cn*n,n-1,f);else;disp(cn);end');
f=@(n)f(1,n,f);

What is not very satisfactory is that you still cannot use this function when directly assigning, a=f(3) still produces an error, since eval does not get a value. 不太令人满意的是,在直接分配时仍然无法使用此功能, a=f(3)仍然会产生错误,因为eval没有得到值。

So my question is, can you actually do a recursive function via anonymous functions that eg calculates factorial in a way that allows eg a=f(3) with relying only on native matlab functions (or functions you can create in the command line, as I did in my example)? 所以我的问题是,您是否可以通过匿名函数实际执行递归函数,例如以允许例如a=f(3)的方式计算阶乘,仅依赖于本机matlab函数(或者您可以在命令行中创建的函数,如我在我的例子中做过)?

PS: I know this does not have any practical use, it is just a challenge on how much you can bend and abuse Matlab's syntax. PS:我知道这没有任何实际用途,这只是对你可以弯曲和滥用Matlab语法的挑战。

We found two possibilites now, both rely on the use of cell arrays. 我们现在发现了两种可能性,都依赖于细胞阵列的使用。 Note that this might not work in Octave. 请注意,这可能不适用于Octave。

The key was an implementation of a case distinction. 关键是案例区分的实施。 The first one that I found, can be found here. 我找到的第一个可以在这里找到

This method makes use of matlabs boolean values, true can be evaluated as 1 while false can be evaluated as 0 . 此方法使用matlabs布尔值,true可以计算为1而false可以计算为0

if_ = @( pred_, cond_ ) cond_{ 2 - pred_ }();

Here we have to provide a condition as first argument, and a 2 element cell array as second argument. 这里我们必须提供一个条件作为第一个参数,一个2元素单元格数组作为第二个参数。 Each cell element should be a function handle that is called if the condition is true/not true. 每个单元格元素应该是一个函数句柄,如果条件为真/不为真,则调用该函数句柄。 Our factorial function would look like this: 我们的阶乘函数看起来像这样:

fac = @(n,f)if_(n>1,{@()n*f(n-1,f),@()1})
factorial_=@(n)fac(n,fac);
factorial_(10)

As @AndrasDeak commented below: The important part here is that we have a cell array of functions and not of values . 正如@AndrasDeak评论如下:这里的重要部分是我们有一个函数的单元格数组而不是 This provides the short circuiting, as n*f(n-1,f) is not evaluated unless we call the corresponding function @()n*f(n-1,f) . 这提供了短路,由于n*f(n-1,f)不评估除非我们调用相应的功能@()n*f(n-1,f)

The second method was found by @beaker and is somewhat more flexible: 第二种方法是由@beaker发现的,并且更灵活一些:

iif = @(varargin) varargin{2*find([varargin{1:2:end}], 1, 'first')}();

This makes use of the fact that you can use varargin (variable amount of arguments) even in anonymous functions. 这利用了即使在匿名函数中也可以使用varargin (可变数量的参数)这一事实。 When you call this function you have to alternate conditions and what should be executed if the condition is true. 当你调用这个函数时,你必须交替条件,如果条件为真,应该执行什么。 This one even allows a switch construct, or a if ... else if ... else if ... (...) else ... construct. 这个甚至允许一个switch构造,或者if ... else if ... else if ... (...) else ...构造。 When called, it will look for the first condition that is true ( find([varargin{1:2:end}], 1, 'first') ) and call the corresponding function. 调用时,它将查找第一个为true的条件( find([varargin{1:2:end}], 1, 'first') )并调用相应的函数。 Our example of the factorial function looks like this: 我们的阶乘函数示例如下所示:

fac = @(n,f)iif(n>1,@()n * f(n-1,f),true,@()1);
factorial_=@(n)fac(n,fac);
factorial_(10)

EDIT: Fun fact: What we are doing with the line 编辑:有趣的事实:我们正在做什么线

 factorial_=@(n)fac(n,fac);

is also known as applying the Y-combinator . 也被称为应用Y-组合子 In fact we can write that as 事实上,我们可以写为

 Y = @(f)@(x)f(x,f);
 factorial_=Y(f);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM