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.
Anonymous recursion is primarily of use in allowing recursion for anonymous functions, particularly when they form closures or are used as callbacks, to avoid having to bind the name of the function. Anonymous recursion primarily consists of calling "the current function", which results in direct recursion.
Recursion is a kind of tricky and smart construction which allows a function to call itself. The Matlab programming language supports it, so a function can call itself during its own execution. Recursive algorithms can be directly implemented in Matlab.
An anonymous function is a function that is not stored in a program file, but is associated with a variable whose data type is function_handle . Anonymous functions can accept multiple inputs and return one output. They can contain only a single executable statement.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With