Preparation
πŸ’‘ ⏐ JavaScript Questions
21. Currying

What is Currying?

Currying is a feature in JavaScript that can be used to convert a function having multiple arguments into multiple functions having a single argument. Instead of taking in all the arguments together, the function takes in one argument, which returns a function taking in another argument, which again returns a function that takes in another argument, and so on until all the arguments are fulfilled.

Example

With currying:

function multiply(a) {
  return (b) => {
    return (c) => {
      return a * b * c;
    };
  };
}
 
console.log(multiply(5)(6)(7)); // 210

Without currying:

function mul(a, b, c) {
  return a * b * c;
}
 
console.log(mul(5, 6, 7)); // 210

Question 1: sum(2)(6)(1)

Explanation: This function demonstrates currying by taking three separate arguments and adding them together in a sequence using nested functions.

function sum(a) {
  return (b) => {
    return (c) => {
      return a + b + c;
    };
  };
}

Question 2: Write a currying function evaluate("sum")(4)(2)

Explanation: This question showcases a curried function evaluate that takes an operation string and two numbers, then performs the corresponding operation (sum, multiply, divide, subtract) based on the string input.

Example:

  • evaluate("sum")(4)(2)
  • evaluate("multiply")(4)(2)
  • evaluate("divide")(4)(2)
  • evaluate("substract")(4)(2);
function evaluate(operation) {
  return (a) => {
    return (b) => {
      if (operation === "sum") return a + b;
      else if (operation === "multiply") return a * b;
      else if (operation === "divide") return a / b;
      else if (operation === "substract") return a - b;
      else return "Invalid Operation!";
    };
  };
}
 
console.log(evaluate("sum")(4)(2)); // 6
console.log(evaluate("multiply")(4)(2)); // 8
console.log(evaluate("divide")(4)(2)); // 2
console.log(evaluate("substract")(4)(2)); // 2
console.log(evaluate("substr")(4)(2)); // Invalid Operation!

Question 4: Infinite Currying -> sum(1)(2)(3)...(n)

Explanation: This example illustrates how currying can be used recursively to handle an indefinite number of arguments, continually adding them together until a termination condition is met.

function addInfinite(a) {
  return function (b) {
    if (b) return addInfinite(a + b);
    return a;
  };
}
 
console.log(addInfinite(5)(2)(4)(8)()); // 19

Question 4: Currying vs Partial Application

Currying

Currying is a transformation of functions that translates a function from callable as f(a, b, c) into callable as f(a)(b)(c). In other words, currying converts a function with multiple arguments into a sequence of functions, each with a single argument. This allows for incrementally applying arguments to a function.

The key characteristics of currying are:

  • Transforms the function: Currying changes the function structure.
  • Fixed arity: The original function’s arity (the number of arguments it accepts) is predefined and fixed.
  • Each function returns a new function: Each stage of application returns another function that expects the next argument.

Example in JavaScript:

function curry(f) {
  // curry a function f
  return function (a) {
    return function (b) {
      return function (c) {
        return f(a, b, c);
      };
    };
  };
}
 
// Original function
function sum(a, b, c) {
  return a + b + c;
}
 
// Curried version of sum
const curriedSum = curry(sum);
console.log(curriedSum(1)(2)(3)); // Outputs 6

Partial Application

Partial application refers to the process of fixing a number of arguments to a function, producing another function of smaller arity. Unlike currying, which always produces single-argument functions, partial application can fix any number of arguments and the resultant function expects the remaining arguments.

The key characteristics of partial application are:

  • Does not change function structure: It produces a function expecting fewer arguments.
  • Variable arity: You can partially apply any subset of arguments.
  • Resultant function calls the original function: Once all arguments are provided, the original function is executed.

Example in JavaScript:

function partial(f, ...fixedArgs) {
  return function (...remainingArgs) {
    return f(...fixedArgs, ...remainingArgs);
  };
}
 
// Original function
function multiply(x, y, z) {
  return x * y * z;
}
 
// Partially applied function
const partialMultiply = partial(multiply, 2, 5);
console.log(partialMultiply(3)); // Outputs 30 (2 * 5 * 3)

Comparison

  • Purpose: Currying is mainly used in functional programming paradigms to enable function composition and higher-order function manipulation. Partial application is used when some arguments to a function are known in advance and you want to reduce the arity of the function accordingly.
  • Use in Programming Languages: Languages like Haskell and Scala implement currying natively. Languages like JavaScript, Python, etc., support partial application more directly through libraries or built-in functions.
  • Flexibility: Partial application is more flexible in terms of the number of arguments you can fix at a time, whereas currying strictly converts a function into a sequence of single-argument functions.

Both currying and partial application are powerful techniques that help make your functions more modular and reusable, enhancing the overall capability to handle functions dynamically in your code.

Question 5: Curry() implementation

Explanation: This code snippet demonstrates a custom implementation of the curry function, which transforms a multi-argument function into a curried function, enabling partial application and composability.It's applied to a simple sum function for demonstration.

function curry(func) {
  return function curriedFunc(...args) {
    // console.log(args.length, func.length);
    if (args.length >= func.length) {
      return func(...args);
    } else {
      return function (...next) {
        return curriedFunc(...args, ...next);
      };
    }
  };
}
 
const sumCurry = (a, b, c) => a + b + c;
 
const totalSum = curry(sumCurry);
console.log(totalSum(1)(6)(5));