Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Successive function application in MATLAB

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.

like image 476
David Yao Avatar asked Apr 06 '15 23:04

David Yao


People also ask

Can you have multiple functions in MATLAB?

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.

Can you have multiple functions in one file MATLAB?

You can write n number of functions in a single m file.


1 Answers

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

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{:});

Currying

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

Caveat

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.
like image 110
knedlsepp Avatar answered Sep 29 '22 21:09

knedlsepp