How do I do successive function application in MATLAB with anonymous functions? Something like the following:
g = @(x) @(y) x+y;
g(1)(2)
However MATLAB gives an error at line 2: ()-indexing must appear last in an index expression.
But the following works:
g = @(x) @(y) x+y;
f = g(1);
f(2)
The script above outputs ans=3.
I am not very familiar with MATLAB but I think the ability to manipulate on the function level makes programming much easier. For example, when I need to compute projections of functions onto some subspace of L^2, the projection operator and normalization etc. all output functions that take additional arguments to evaluate to a numerical answer.
These are called nested functions, and these can only be called from within the function they are nested. They can also have access to variables in functions in which they are nested, which makes them quite useful albeit slightly tricky to work with.
You can write n number of functions in a single m file.
MATLAB doesn't support single expression calls like y = g(1)(2)
to function handles returned by functions. You can however work your way around this limitation by using temporary variables:
g1 = g(1);
y = g1(2);
As an alternative you could build your own function to wrap around this functionality.
A recursive approach could be:
function f = fevalIterated(f, varargin)
if ~isempty(varargin)
f = fevalIterated(f(varargin{1}), varargin{2:end});
end
Instead of y = g(1)(2)
you would call y = fevalIterated(g, 1, 2)
.
The iterative approach to do this might be faster:
function f = fevalIterated(f, varargin)
for i = 1:numel(varargin)
f = f(varargin{i});
end
As you were asking about the concept of currying in MATLAB, which is really similar to this:
Un-currying would mean to convert a function @(x) @(y) @(z) x+y+z
to a function @(x,y,z) x+y+z
. This is a very similar concept and you can thus reuse the functionality of fevalIterated
to build a function uncurry
that can be used like this:
g = uncurry(@(x) @(y) @(z) x+y+z);
y = g(1,2,3)
The function uncurry
would be defined as:
function uncurried = uncurry(f)
uncurried = @(varargin) fevalIterated(f, varargin{:});
To curry a function @(x,y,z) x+y+z
would mean to convert it to @(x) @(y) @(z) x+y+z
.
Here is a recursive implementation of curry
:
function f = curry(f,N)
if N>1
f = @(first) curry(@(varargin)f(first,varargin{:}), N-1);
end
A (faster) iterative implementation would look like this:
function f = curry(f,N)
for i = 1:N-1
f = @(varargin) @(last) f(varargin{:}, last);
end
You can call both via f = curry(@(x,y,z) x+y+z, 3)
.
Although you can do all this in MATLAB, you might suffer from a noticable performance drop if you overdo the whole function handle calling thingy.
f = @(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15) ...
(x1+x2+x3+x4+x5+x6+x7+x8+x9+x10+x11+x12+x13+x14+x15);
%%// Currying vs Comma separated list expansion
%// Comma separated list expansion
tic;
[C{1:15}] = deal(12345);
f(C{:});
toc;
%// Elapsed time is 0.000146 seconds.
%// Currying
g = curry(f,15);
tic;
for i = 1:15
g = g(12345);
end
toc;
%// Elapsed time is 0.015679 seconds.
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