Flexible Curry Function
Prompt
Implement a curry utility function that allows flexible function invocation with partial argument application.
Requirements
- Create a function that can be called with varying argument counts
- Support multiple invocation patterns
- Ignore excess arguments beyond function's arity
Example
const multiply = (a, b, c) => a * b * c;
let curriedMultiply = curry(multiply);
console.log(curriedMultiply(2, 3, 4)); // 24
console.log(curriedMultiply(2)(3, 4)); // 24
console.log(curriedMultiply(2)(3)(4)); // 24
console.log(curriedMultiply(2, 3)(4)); // 24
console.log(curriedMultiply(2, 3, 4, 5)); // 24 (Extra arguments are ignored)
Playground
Solution
Explanation
Let's break down how this curry function works step by step.
First, we need to know how many arguments the original function expects. We can get this using the length
property of the function.
const arity = fn.length;
Next, we create an inner function called curried
that uses the rest parameter syntax to collect all arguments passed to it.
function curried(...args) {
// implementation
}
Now comes the core logic. We need to handle two cases.
- First, if we have enough arguments (or more), execute the function:
if (args.length >= arity) {
return fn(...args.slice(0, arity));
}
Here we use slice(0, arity)
to handle the requirement of ignoring excess arguments. For example, if our function needs 3 arguments but gets 4, we only take the first 3.
- Second, if we don't have enough arguments yet, return a new function that waits for more.
return function(...moreArgs) {
return curried(...args, ...moreArgs);
};
This is where the magic happens. We return a new function that:
- Takes more arguments using rest parameters
- Combines the previously collected arguments with the new ones
- Calls
curried
again with all arguments
This recursive pattern continues until we have enough arguments to execute the original function.
Let's see how it works with an example:
curriedMultiply(2)(3)(4)
-
First call
curriedMultiply(2)
:args = [2]
- Not enough arguments (need 3)
- Returns a new function
-
Second call with
(3)
:args = [2, 3]
- Still not enough arguments
- Returns another function
-
Final call with
(4)
:args = [2, 3, 4]
- We have all 3 arguments
- Executes
multiply(2, 3, 4)
- Returns 24
The beauty of this implementation is that it works with any combination of argument groupings, as long as we eventually provide all the required arguments.
Let's see another example:
curriedMultiply(2, 3)(4)
-
First call
curriedMultiply(2, 3)
:args = [2, 3]
- Not enough arguments (need 3)
- Returns a new function
-
Second call with
(4)
:args = [2, 3, 4]
- We have all 3 arguments
- Executes
multiply(2, 3, 4)
- Returns 24
This demonstrates how the curry function can be used with different argument groupings, and it will always execute the original function with the correct number of arguments.
What is Arity?
Arity is the number of arguments a function expects or can accept. In JavaScript, it represents the count of parameters defined in a function's declaration.
function add(a, b) { // Arity of 2
return a + b;
}
function greet() { // Arity of 0
console.log("Hello");
}
console.log(add.length); // Outputs: 2
console.log(greet.length); // Outputs: 0
Arity helps in techniques like currying, function overloading, and understanding function behavior.