Recursive Anonymous Function Matlab

痴心易碎 提交于 2019-12-17 05:12:08

问题


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.

So my question is, can you actually do a recursive function via anonymous functions that e.g. calculates factorial in a way that allows e.g. 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)?

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.


回答1:


We found two possibilites now, both rely on the use of cell arrays. Note that this might not work in 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.

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. 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. 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).

The second method was found by @beaker and is somewhat more flexible:

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. 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. When called, it will look for the first condition that is true ( find([varargin{1:2:end}], 1, 'first') ) and call the corresponding function. 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. In fact we can write that as

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


来源:https://stackoverflow.com/questions/32237198/recursive-anonymous-function-matlab

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!