As MATLAB has a hard maximum of 10 input arguments it's possible, but ugly, to implement a curry function in this manner:
%% turns a standard function into a curried one
% if g has 3 input arguments then you can call:
% h = curry(g)
% h(1)(2)(3) == g(1, 2, 3)
% Matlab doesn't like h(1)(2)(3), but in principle it works.
function fOut = curry(fIn)
fOut = fIn;
% can't curry a vararg function
if (nargin(fOut) < 0)
return
end
if (nargin(fOut) == 10)
fOut = @(bind)(curry(@(free1, free2, free3, free4, free5, free6, free7, free8, free9) (fIn(bind, free1, free2, free3, free4, free5, free6, free7, free8, free9))));
return
end
if (nargin(fOut) == 9)
fOut = @(bind)(curry(@(free1, free2, free3, free4, free5, free6, free7, free8) (fIn(bind, free1, free2, free3, free4, free5, free6, free7, free8))));
return
end
if (nargin(fOut) == 8)
fOut = @(bind)(curry(@(free1, free2, free3, free4, free5, free6, free7) (fIn(bind, free1, free2, free3, free4, free5, free6, free7))));
return
end
if (nargin(fOut) == 7)
fOut = @(bind)(curry(@(free1, free2, free3, free4, free5, free6) (fIn(bind, free1, free2, free3, free4, free5, free6))));
return
end
if (nargin(fOut) == 6)
fOut = @(bind)(curry(@(free1, free2, free3, free4, free5) (fIn(bind, free1, free2, free3, free4, free5))));
return
end
if (nargin(fOut) == 5)
fOut = @(bind)(curry(@(free1, free2, free3, free4) (fIn(bind, free1, free2, free3, free4))));
return
end
if (nargin(fOut) == 4)
fOut = @(bind)(curry(@(free1, free2, free3) (fIn(bind, free1, free2, free3))));
return
end
if (nargin(fOut) == 3)
fOut = @(bind)(curry(@(free1, free2) (fIn(bind, free1, free2))));
return
end
if (nargin(fOut) == 2)
fOut = @(bind)(curry(@(free1) (fIn(bind, free1))));
return
end
end
Is there a less horrible way to do this?
Initially, I tried using varargin
which is how I assume the answer will look. Here's what I had at that time:
function fOut = curry(fIn)
fOut = fIn;
% can't curry a vararg function (nargin = -1) or a function with less than
% arity of 2
if (nargin(fOut) < 2)
return
end
fOut = @(bind)(curry(@(varargin)(fIn(bind, varargin{:}))));
end
1 Answer 1
The first thing I'd do would be to use a switch
statement instead of the if
statements. It cleans it up a bunch.
function fOut = curry(fIn)
fOut = fIn;
switch nargin(fOut)
case 5
fOut = @(bind)(curry(@(free1, free2, free3, free4) (fIn(bind, free1, free2, free3, free4))));
case 4
fOut = @(bind)(curry(@(free1, free2, free3) (fIn(bind, free1, free2, free3))));
case 3
fOut = @(bind)(curry(@(free1, free2) (fIn(bind, free1, free2))));
case 2
fOut = @(bind)(curry(@(free1) (fIn(bind, free1))));
otherwise
% Do nothing,
end
return
Also, more than 10 inputs are ok in Matlab:
f = @(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)cat(2,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12);
Worked in R2008b and in R2012b:
f(1,2,3,4,5,6,7,8,9,0,1,2)
ans =
1 2 3 4 5 6 7 8 9 0 1 2
Of note, there is a curry
function in the functional library on MatlabCentral. (I would have commented this, but I don't have the rep, yet...)
-
\$\begingroup\$ Also: Why not use
varargin
? As long as the functional interface is consistent and always uses it, then wouldn't it work? I will have to look into currying a bit more to understand it better. \$\endgroup\$aepound– aepound2015年05月15日 00:50:06 +00:00Commented May 15, 2015 at 0:50 -
\$\begingroup\$ currying simply takes a function and returns a series of functions that only take one argument. If you have a function
f
that takes 3 arguments, it transforms it into 3 chained functions (let's call the firstg
) that each take a single argument. Soresult = f(1, 2, 3);
is equivalent toresult = g(1)(2)(3)
(the syntax of which Matlab doesn't seem to like, so technicallyh = g(1);
theni = h(2);
thenresult = i(3);
) \$\endgroup\$OmnipotentEntity– OmnipotentEntity2015年05月15日 01:46:10 +00:00Commented May 15, 2015 at 1:46