Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
How to uncurry a function up to depth n in JavaScript?
In JavaScript, a function is considered "curried" if it takes one or more arguments and returns a new function that expects the remaining arguments. Currying is a powerful technique that can be used to create new functions from existing ones, or to "uncurry" a function up to depth n.
Why do we uncurry a function?
There are several reasons why you might want to uncurry a function. For example, you may want to ?
Use a curried function in a context where a non-curried function is expected
Convert a curried function to a non-curried form to make it easier to read or debug
Optimize a curried function for performance
Understanding Currying First
Before uncurrying, let's see a basic curried function:
<!DOCTYPE html>
<html>
<head>
<title>Curried Function Example</title>
</head>
<body>
<div id="result1"></div>
<script>
// Curried function - takes one argument at a time
function curriedAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
}
}
}
// Using the curried function
let result = curriedAdd(1)(2)(3);
document.getElementById("result1").innerHTML = "Curried result: " + result;
</script>
</body>
</html>
Curried result: 6
Method 1: Using Function.prototype.apply
The "Function.prototype.apply" method can be used to uncurry a function up to depth n. Here's how to create an uncurried version:
<!DOCTYPE html>
<html>
<head>
<title>Uncurry with Apply</title>
</head>
<body>
<div id="result2"></div>
<script>
// Original curried function
function curriedAdd(a) {
return function(b) {
return a + b;
}
}
// Uncurry function using apply
function uncurry(fn) {
return function(...args) {
return args.reduce((acc, arg) => acc(arg), fn);
};
}
// Create uncurried version
let uncurriedAdd = uncurry(curriedAdd);
// Use it with multiple arguments at once
let result = uncurriedAdd(5, 3);
document.getElementById("result2").innerHTML = "Uncurried result: " + result;
</script>
</body>
</html>
Uncurried result: 8
Method 2: Manual Uncurrying to Specific Depth
You can manually uncurry a function to a specific depth by creating a wrapper function:
<!DOCTYPE html>
<html>
<head>
<title>Manual Uncurrying</title>
</head>
<body>
<div id="result3"></div>
<script>
// Curried function with depth 3
function curriedMultiply(a) {
return function(b) {
return function(c) {
return a * b * c;
}
}
}
// Uncurry to depth 3
function uncurryToDepth3(fn) {
return function(a, b, c) {
return fn(a)(b)(c);
};
}
// Create uncurried version
let uncurriedMultiply = uncurryToDepth3(curriedMultiply);
// Use with all arguments at once
let result = uncurriedMultiply(2, 3, 4);
document.getElementById("result3").innerHTML = "Uncurried multiply result: " + result;
</script>
</body>
</html>
Uncurried multiply result: 24
Generic Uncurry Function
Here's a more flexible approach that can handle any depth:
<!DOCTYPE html>
<html>
<head>
<title>Generic Uncurry Function</title>
</head>
<body>
<div id="result4"></div>
<script>
// Generic uncurry function
function uncurryN(fn, n) {
return function(...args) {
if (args.length >= n) {
let result = fn;
for (let i = 0; i < n; i++) {
result = result(args[i]);
}
return result;
}
// Return partially applied function if not enough args
return uncurryN(args.reduce((f, arg) => f(arg), fn), n - args.length);
};
}
// Curried function
function curriedSum(a) {
return function(b) {
return function(c) {
return function(d) {
return a + b + c + d;
}
}
}
}
// Uncurry to depth 4
let uncurriedSum = uncurryN(curriedSum, 4);
let result = uncurriedSum(1, 2, 3, 4);
document.getElementById("result4").innerHTML = "Generic uncurry result: " + result;
</script>
</body>
</html>
Generic uncurry result: 10
Comparison of Methods
| Method | Flexibility | Performance | Use Case |
|---|---|---|---|
| Manual Uncurry | Limited | Fast | Known depth, simple functions |
| Generic Uncurry | High | Moderate | Variable depth, reusable |
| Reduce-based | High | Good | Dynamic argument handling |
Conclusion
Uncurrying functions allows you to convert curried functions back to regular multi-argument functions. Use manual uncurrying for known depths or generic approaches for flexible solutions.
