14/16 lessons88%

Currying in Functional Programming

Currying is a functional programming technique where a function is transformed to take arguments one at a time. Instead of taking all arguments at once, a curried function returns another function that takes the next argument, and so on, until all arguments are provided. This technique enables more reusable, flexible, and composable code.

What is Currying?

Currying converts a function with multiple arguments into a series of functions, each taking a single argument.

Standard Function:

javascript
1
2
3
4
5
          function add(a, b) {
  return a + b;
}

console.log(add(2, 3)); // 5
        

Curried Version:

javascript
1
2
3
4
5
6
7
8
9
          function curriedAdd(a) {
  return function (b) {
    return a + b;
  };
}

const addTwo = curriedAdd(2);
console.log(addTwo(3)); // 5
console.log(curriedAdd(2)(3)); // 5
        

Currying Benefits

  1. 1
    Function Reusability: Preconfigure arguments to create specialized functions.
  2. 2
    Function Composition: Simplifies the chaining of functions.
  3. 3
    Improved Readability: Logical flow becomes more explicit.

Manual Currying with Closures

Closures play a vital role in implementing currying. Let’s create a manual example of a curried function.

javascript
1
2
3
4
5
6
7
8
9
          function multiply(a) {
  return function (b) {
    return function (c) {
      return a * b * c;
    };
  };
}

console.log(multiply(2)(3)(4)); // 24
        

Here, each level of the function remembers its input and passes it along to the next level.

Using a Helper Function to Curry

Instead of manually currying, we can create a generic currying utility.

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
          function curry(func) {
  return function curried(...args) {
    if (args.length >= func.length) {
      return func(...args);
    } else {
      return (...nextArgs) => curried(...args, ...nextArgs);
    }
  };
}

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

const curriedSum = curry(sum);
console.log(curriedSum(1)(2)(3)); // 6
console.log(curriedSum(1, 2)(3)); // 6
console.log(curriedSum(1)(2, 3)); // 6
        

Practical Use Case: Filtering Data

Suppose you need a reusable function to filter a dataset.

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
          const filterBy = curry((key, value, array) => {
  return array.filter(item => item[key] === value);
});

const filterByCategory = filterBy("category");

const products = [
  { name: "Laptop", category: "Electronics" },
  { name: "Shirt", category: "Clothing" },
  { name: "Phone", category: "Electronics" },
];

console.log(filterByCategory("Electronics")(products));

// [{ name: "Laptop", category: "Electronics" }, { name: "Phone", category: "Electronics" }]
        

Built-in Support: Arrow Functions and Currying

JavaScript arrow functions make curried functions concise.

javascript
1
2
3
          const multiply = a => b => c => a * b * c;

console.log(multiply(2)(3)(4)); // 24
        

When to Use Currying?

  1. 1
    Preconfigured Functions: Create functions with some arguments pre-filled.
  2. 2
    Functional Composition: Chain operations easily by partially applying functions.
  3. 3
    Simplified Testing: Test parts of the function independently.

Common Pitfalls and Best Practices

  1. 1
    Over-currying: Don’t curry unnecessarily, as it might make the code harder to understand.
  2. 2
    Flexible Implementation: Use a currying utility for larger projects.

Conclusion

  • Currying transforms a function into smaller, single-argument functions.
  • It improves reusability and composition in functional programming.
  • JavaScript supports currying through closures and utility functions.