3
\$\begingroup\$

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
\$\endgroup\$
0

1 Answer 1

4
\$\begingroup\$

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

\$\endgroup\$
2
  • \$\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
    Commented 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 first g) that each take a single argument. So result = f(1, 2, 3); is equivalent to result = g(1)(2)(3) (the syntax of which Matlab doesn't seem to like, so technically h = g(1); then i = h(2); then result = i(3);) \$\endgroup\$ Commented May 15, 2015 at 1:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.