Curry

Updated on 21 May, 2025
Curry header image

Problem Statement

Given a function fn, the task is to return a curried version of that function. Currying is a transformation of functions that translates a function from callable as f(a, b, c) into callable as f(a)(b)(c). Essentially, it breaks down a function that takes multiple arguments into a series of functions that each take only one argument.

For example, consider a function sum that calculates the sum of three numbers:

javascript
function sum(a, b, c) {
  return a + b + c;
}

The curried version of sum, let's say curriedSum, can be executed as curriedSum(1)(2)(3), curriedSum(1, 2)(3), or even curriedSum(1)(2, 3). Each of these calls would yield the same result as the original sum(1, 2, 3) call, demonstrating the flexibility of curried functions to receive the same total number of arguments through multiple calls.

Examples

Example 1

Input:

fn = function sum(a, b, c) { return a + b + c; }
inputs = [[1],[2],[3]]

Output:

6

Explanation:

The code being executed is:
const curriedSum = curry(fn);
curriedSum(1)(2)(3) === 6;
curriedSum(1)(2)(3) should return the same value as sum(1, 2, 3).

Example 2

Input:

fn = function sum(a, b, c) { return a + b + c; }
inputs = [[1,2],[3]]

Output:

6

Explanation:

curriedSum(1, 2)(3) should return the same value as sum(1, 2, 3).

Example 3

Input:

fn = function sum(a, b, c) { return a + b + c; }
inputs = [[],[],[1,2,3]]

Output:

6

Explanation:

You should be able to pass the parameters in any way, including all at once or none at all.
curriedSum()()(1, 2, 3) should return the same value as sum(1, 2, 3).

Example 4

Input:

fn = function life() { return 42; }
inputs = [[]]

Output:

42

Explanation:

currying a function that accepts zero parameters should effectively do nothing.
curriedLife() === 42

Constraints

  • 1 <= inputs.length <= 1000
  • 0 <= inputs[i][j] <= 105
  • 0 <= fn.length <= 1000
  • inputs.flat().length == fn.length
  • function parameters explicitly defined
  • If fn.length > 0 then the last array in inputs is not empty
  • If fn.length === 0 then inputs.length === 1

Approach and Intuition

To tackle this problem, understanding the examples and constraints leads to devising the right approach.

Intuition

The fundamental goal of currying a function is to break down a multi-argument function into a series of unary (single-argument) functions. Each unary function returns another function, expecting the next argument, until all arguments have been received, at which point the original function's result is computed and returned.

Examples

Example 1

Input:

fn = function sum(a, b, c) { return a + b + c; }
inputs = [[1],[2],[3]]

Output:

6

Explanation:

The code being executed is:
const curriedSum = curry(fn);
curriedSum(1)(2)(3) === 6;
curriedSum(1)(2)(3) should return the same value as sum(1, 2, 3).

Example 2

Input:

fn = function sum(a, b, c) { return a + b + c; }
inputs = [[1,2],[3]]

Output:

6

Explanation:

curriedSum(1, 2)(3) should return the same value as sum(1, 2, 3).

Example 3

Input:

fn = function sum(a, b, c) { return a + b + c; }
inputs = [[],[],[1,2,3]]

Output:

6

Explanation:

You should be able to pass the parameters in any way, including all at once or none at all.
curriedSum()()(1, 2, 3) should return the same value as sum(1, 2, 3).

Example 4

Input:

fn = function life() { return 42; }
inputs = [[]]

Output:

42

Explanation:

currying a function that accepts zero parameters should effectively do nothing.
curriedLife() === 42

Constraints

  • 1 <= inputs.length <= 1000
  • 0 <= inputs[i][j] <= 105
  • 0 <= fn.length <= 1000
  • inputs.flat().length == fn.length
  • function parameters explicitly defined
  • If fn.length > 0 then the last array in inputs is not empty
  • If fn.length === 0 then inputs.length === 1

Approach Based on Examples

  1. Example 1:

    • Input: fn = sum(a, b, c) and inputs = [[1], [2], [3]]
    • Here, the curried function separates each argument into its function call: curriedSum(1)(2)(3).
    • The final result after passing all arguments separately is 6, identical to sum(1, 2, 3).
  2. Example 2:

    • Input: inputs = [[1,2],[3]]
    • This demonstrates partial application where the first curried function takes multiple arguments in one go: curriedSum(1, 2)(3).
    • The result remains the same as passing all arguments at once.
  3. Example 3:

    • Input: inputs = [[],[],[1,2,3]]
    • Illustrates that the curried function should handle calls with no arguments initially and still function correctly when all arguments passed later: curriedSum()()(1, 2, 3).
    • This flexibility in handling input is key in a curried function.
  4. Example 4:

    • Input: fn = function life() { return 42; }
    • Even without any parameters, currying should not alter the behavior or result of the function, indicating curriedLife() should still return 42.

These outlined steps from the examples demonstrate the essential characteristic of currying: flexibility in how input is received while guaranteeing the output remains consistent with the original function's behavior given the same total input.

Solutions

  • JavaScript
js
var curryFunction = function(func) {
  return function curriedFunc(...params) {
    if (params.length >= func.length) {
      return func.apply(this, params);
    }

    return curriedFunc.bind(this, ...params);
  };
};

The provided JavaScript code defines a function named curryFunction designed to transform a given function into its curried version. Currying is a technique where a function with multiple arguments is transformed into a sequence of nested functions, each taking a single argument. This allows for partial function application.

  • The curryFunction takes func as an argument, which is the function to be curried.
  • Inside, it returns a new function curriedFunc. This nested function accumulates parameters passed to it (...params).
  • Check if the number of parameters provided is at least equal to the expected number of parameters (func.length). If true, it calls the original function func using apply to pass the collected parameters.
  • If the accumulated parameters are insufficient, curriedFunc uses bind to create a new function, pre-filled with the collected parameters for the next call.

This approach maximizes flexibility and reusability in functional programming, allowing you to create more specific functions from general ones by fixing some arguments ahead of time.

Comments

No comments yet.