Skip to main content

Curry - Solution & Explanation

MediumPremiumFree on FleetCode4 min read
Practice this problem

Problem Statement

Given a function fn, return a curried version of that function.

curried function is a function that accepts fewer or an equal number of parameters as the original function and returns either another curried function or the same value the original function would have returned.

In practical terms, if you called the original function like sum(1,2,3), you would call the curried version like csum(1)(2)(3)csum(1)(2,3)csum(1,2)(3), or csum(1,2,3). All these methods of calling the curried function should return the same value as the original.

 

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 Overview

Problem Overview: The task asks you to convert a normal function into a curried version. Instead of passing all arguments at once, the returned function should accept arguments across multiple calls and only execute the original function when enough parameters have been collected.

Approach 1: Recursive Argument Collector (O(n) time, O(n) space)

The common solution uses a closure that keeps track of the arguments passed so far. Each call gathers new parameters and checks whether the total number of collected arguments is at least the original function's arity (fn.length). If enough arguments exist, execute fn(...args). Otherwise return another function that continues collecting arguments. Recursion naturally models the repeated chaining behavior (curried(a)(b)(c)). Time complexity is O(n) where n is the number of arguments eventually supplied, since each argument is processed once. Space complexity is O(n) due to stored arguments and closure scope.

This technique relies heavily on JavaScript closures and functional programming behavior. The closure preserves previously provided arguments between calls, which allows partial application without global state. If you are reviewing functional design patterns, this pattern closely relates to functional programming and recursion concepts.

Approach 2: Iterative Closure with Argument Buffer (O(n) time, O(n) space)

Another implementation keeps an argument buffer inside a closure rather than passing arguments recursively. Every time the returned function is called, append new parameters into an array. After appending, check whether the buffer length reaches fn.length. Once the required count is met, call the original function using the buffered arguments. The logic is iterative but still depends on closures to maintain state across invocations. Time complexity remains O(n) since each argument is appended once, and space complexity is also O(n) for storing the collected parameters.

Approach 3: Using Function.bind for Partial Application (O(n) time, O(n) space)

JavaScript's Function.bind can partially apply arguments to a function. You can repeatedly bind arguments until the total count satisfies the required arity. Each bind returns a new function with pre-filled parameters. When enough arguments accumulate, invoke the original function. Although elegant, this method creates multiple bound function instances, which can introduce additional overhead. Complexity still remains O(n) time and O(n) space due to argument accumulation.

Recommended for interviews: The recursive closure approach is the most expected answer. It directly demonstrates understanding of closures, argument spreading, and functional composition. Showing a simple brute-style argument collector proves you understand the problem, while the recursive curry implementation highlights deeper JavaScript knowledge and clean functional design.

Solution

Code

TypeScript

Try this approach in the editor →

Detailed Complexity Analysis

ApproachTimeSpaceWhen to Use
Recursive Argument CollectorO(n)O(n)Most common interview solution; clean implementation using closures and recursion
Iterative Closure with Argument BufferO(n)O(n)Useful when you prefer explicit state management rather than recursion
Function.bind Partial ApplicationO(n)O(n)Demonstrates JavaScript built-in partial application, but less common in interviews

Video Solution

Curry - Leetcode 2632 - JavaScript 30-Day Challenge • NeetCodeIO • 13,047 views views

Watch 5 more video solutions →

Frequently Asked Questions

Is Curry easy or hard?
Curry is generally considered a medium-level problem. The implementation itself is short, but it requires understanding closures, function arity, and how chained function calls accumulate arguments. Developers unfamiliar with functional programming patterns may initially find it tricky.
Curry Python/Java solution
Currying is most common in JavaScript because functions can easily return other functions and access argument length dynamically. In Python or Java, similar behavior can be implemented using nested functions or functional interfaces, but the syntax is less direct compared to JavaScript closures.
How to solve Curry in O(n)?
Create a function that returns another function responsible for collecting arguments. Store the arguments in a closure and compare their count with fn.length, which represents the expected number of parameters. If the count is sufficient, call fn with the accumulated arguments; otherwise return another function to continue collecting them.
What is the best approach for Curry?
The recursive closure approach is the standard solution. It collects arguments across calls and checks whether the total count reaches the original function's arity using fn.length. Once enough parameters are gathered, the original function executes. This approach runs in O(n) time and O(n) space where n is the number of arguments.
Is Curry asked at Google/Amazon/Meta?
Currying and partial application concepts appear in frontend and JavaScript-heavy interviews, especially for companies focusing on functional programming patterns. While this exact problem may not always appear, the concept of implementing curry functions and closures is common in JavaScript interviews at large tech companies.
What data structure is used in Curry?
The solution primarily uses arrays to store collected arguments and closures to preserve state across function calls. The array holds the accumulated parameters while the closure ensures those values remain accessible between chained calls.
What is the time complexity of Curry?
The time complexity is O(n), where n represents the total number of arguments passed before the original function executes. Each argument is processed exactly once when collected and forwarded to the final function call. Space complexity is also O(n) due to stored arguments inside closures.

Ready to solve this problem?

Practice Curry with our built-in code editor and test cases.

Practice on FleetCode