Jyoti Prasad Pal
Jyoti Prasad Pal

Reputation: 1629

Uncurry a curried function of n parameters in javascript

If f :: a -> b -> c is curried then uncurry(f) can be defined as:

uncurry :: (a -> b -> c) -> ((a, b) -> c)

I'm trying to implement the above function in javascript. Is my below implementation correct and generic enough or are there are any better solution?

const uncurry = f => {
  if (typeof f != "function" || f.length == 0)
    return f;

  return function()
  {     
    for (let i = 0; i < arguments.length; i++){
      f = f(arguments[i]);
    }

    return f;
  };
}


const curry = f => a => b => f(a, b);
const curriedSum = curry((num1, num2) => num1 + num2);
console.log(curriedSum(2)(3)); //5

console.log(uncurry(curriedSum)(2, 3)); //5

Upvotes: 7

Views: 1435

Answers (2)

user6445533
user6445533

Reputation:

Your uncurry has three issues:

  1. if not all expected arguments are passed it returns a curried function (which isn't the behavior of a normal, uncurried function)
  2. it can't deal with unnecessary arguments
  3. the implementation isn't very functional since you don't reuse anything

Here is a more functional approach:

const id = x => x;
const uncurry = f => (x, y) => f(x)(y);

const uncurryn = n => f => (...xs) => {
  const next = acc => xs => xs.reduce(uncurry(id), acc);
  if (n > xs.length) throw new RangeError("too few arguments");
  return next(f) (xs.slice(0, n));
}

const sum = x => y => z => x + y + z;

try {uncurryn(3)(sum)(1, 2)} catch(e) {console.log(e.message)}
console.log(uncurryn(3)(sum)(1, 2, 3));
console.log(uncurryn(3)(sum)(1, 2, 3, 4));

uncurryn ignores unnecessary arguments like any other function in Javascript. It reuses uncurry, reduce and id.

If too few arguments are passed it throws an error, since it isn't clear in each case, which value should be returned (NaN, undefined).

Upvotes: 3

sielakos
sielakos

Reputation: 2404

It is not bad, but you assume that f is function until you loop through all arguments.

Also if you are using es6 consider using rest operator instead of arguments. And for ... of is nicer syntax in es6 to loop through values of array.

const uncurry = f => {
  if (typeof f !== "function" || f.length == 0)
    return f;

  return (...args) => {     
    for (let arg of args) {
      if (typeof f !== "function") {
        return f;
      }
      
      f = f(arg);
    }

    return f;
  };
}




const curry = f => a => b => f(a, b);
const curriedSum = curry((num1, num2) => num1 + num2);
console.log(curriedSum(2)(3)); //5

console.log(uncurry(curriedSum)(2, 3)); //5

Upvotes: 2

Related Questions