MATLAB中的连续函数应用

Dav*_*Yao 5 matlab functional-programming anonymous-function currying

如何在MATLAB中使用匿名函数进行连续函数应用?类似于以下内容:

g = @(x) @(y) x+y;
g(1)(2)
Run Code Online (Sandbox Code Playgroud)

但是,MATLAB在第2行给出错误:() - 索引必须出现在索引表达式的最后.

但以下工作:

g = @(x) @(y) x+y;
f = g(1);
f(2)
Run Code Online (Sandbox Code Playgroud)

上面的脚本输出ans = 3.

我对MATLAB不是很熟悉,但我认为在函数级别上操作的能力使编程变得更加容易.例如,当我需要在L ^ 2的某个子空间上计算函数的投影时,投影算子和规范化等所有输出函数都需要额外的参数来评估数值答案.

kne*_*epp 5

MATLAB不支持单个表达式调用,比如y = g(1)(2)函数返回的函数句柄.但是,您可以使用临时变量来解决此限制:

g1 = g(1); 
y = g1(2);
Run Code Online (Sandbox Code Playgroud)

作为替代方案,您可以构建自己的函数来包装此功能.

递归方法可以是:

function f = fevalIterated(f, varargin)
if ~isempty(varargin)
    f = fevalIterated(f(varargin{1}), varargin{2:end});
end
Run Code Online (Sandbox Code Playgroud)

而不是y = g(1)(2)你会打电话y = fevalIterated(g, 1, 2).

执行此操作的迭代方法可能更快:

function f = fevalIterated(f, varargin)
for i = 1:numel(varargin)
    f = f(varargin{i});
end
Run Code Online (Sandbox Code Playgroud)

正如您在MATLAB中询问currying的概念,这与此非常类似:

取消钻营

解除干扰意味着将函数转换@(x) @(y) @(z) x+y+z为函数@(x,y,z) x+y+z.这是一个非常相似的概念,因此您可以重用功能fevalIterated来构建uncurry可以像这样使用的函数:

g = uncurry(@(x) @(y) @(z) x+y+z);
y = g(1,2,3)
Run Code Online (Sandbox Code Playgroud)

该功能uncurry定义为:

function uncurried = uncurry(f)
uncurried = @(varargin) fevalIterated(f, varargin{:});
Run Code Online (Sandbox Code Playgroud)

哗众取宠

咖喱函数@(x,y,z) x+y+z意味着将其转换为@(x) @(y) @(z) x+y+z.

这是一个递归实现curry:

function f = curry(f,N)
if N>1
    f = @(first) curry(@(varargin)f(first,varargin{:}), N-1);
end
Run Code Online (Sandbox Code Playgroud)

(更快)迭代实现看起来像这样:

function f = curry(f,N)
for i = 1:N-1
    f = @(varargin) @(last) f(varargin{:}, last);
end
Run Code Online (Sandbox Code Playgroud)

你可以通过两个来电话f = curry(@(x,y,z) x+y+z, 3).

警告

虽然你可以在MATLAB中完成所有这些工作,但如果你过度使用调用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.
Run Code Online (Sandbox Code Playgroud)