Implementing Currying with Placeholders in JavaScript



What is Currying with Placeholders?

Currying is a technique in functional programming where a function with multiple arguments is transformed into a sequence of functions, each with a single argument. Placeholders add an extra layer of flexibility by allowing you to skip certain arguments and provide them later.

Real Interview Insights

Interviewers might ask you to:

  • Implement a currying function with placeholder support.
  • Explain the advantages of using placeholders in currying.
  • Demonstrate how to use currying with placeholders in practical scenarios.

Implementing Currying with Placeholders

Let's start with an implementation of a currying function that supports placeholders:

function curry(func) {
  return function curried(...args) {
    const placeholder = curry.placeholder;
    const validArgs = args.filter(arg => arg !== placeholder);
 
    if (validArgs.length >= func.length) {
      return func.apply(this, validArgs);
    } else {
      return function(...nextArgs) {
        const combinedArgs = args.map(arg => arg === placeholder && nextArgs.length ? nextArgs.shift() : arg).concat(nextArgs);
        return curried.apply(this, combinedArgs);
      };
    }
  };
}
 
curry.placeholder = '_';
Explanation:
  • Placeholder Definition: Define a placeholder (curry.placeholder) to represent skipped arguments.
  • Valid Arguments: Filter out placeholder values to determine if the number of provided arguments meets the original function's arity.
  • Combined Arguments: Combine the current arguments with the next set of arguments, replacing placeholders with actual values as they are provided.

Practical Example

Consider a function that subtracts three numbers:

function subtract(a, b, c) {
  return a - b - c;
}
 
const curriedSubtract = curry(subtract);
 
console.log(curriedSubtract(10, '_', 5)(3)); // Output: 2
console.log(curriedSubtract('_', 3)(10, 5)); // Output: 2
console.log(curriedSubtract(10)('_', 5)(3)); // Output: 2

In this example:

  • The subtract function is curried using the curry function.
  • The placeholder (_) is used to skip arguments, allowing them to be provided later.

Advanced Currying: Handling Multiple Use Cases with Placeholders

Let's further enhance our currying function to handle more complex scenarios:

function curry(func) {
  return function curried(...args) {
    const placeholder = curry.placeholder;
 
    const hasPlaceholder = args.includes(placeholder);
    const hasAllArgs = args.filter(arg => arg !== placeholder).length >= func.length;
 
    if (hasAllArgs && !hasPlaceholder) {
      return func.apply(this, args);
    } else {
      return function(...nextArgs) {
        const combinedArgs = args.map(arg => arg === placeholder && nextArgs.length ? nextArgs.shift() : arg).concat(nextArgs);
        return curried.apply(this, combinedArgs);
      };
    }
  };
}
 
curry.placeholder = '_';
 
// Example with varying arguments and placeholders
function multiply(a, b, c, d) {
  return a * b * c * d;
}
 
const curriedMultiply = curry(multiply);
 
console.log(curriedMultiply(2)('_', 4)(3, '_')(5)); // Output: 120
console.log(curriedMultiply('_', 3)(2, '_')(4, 5)); // Output: 120
Key Points:
  • Placeholder Handling: Ensure that the function checks for placeholders and combines arguments appropriately.
  • Flexible Argument Handling: Allow the function to be called with arguments in any order, using placeholders to skip and provide arguments later.

Coding Challenge: Currying with Multiple Placeholders

For a deeper understanding, try this coding challenge:

Challenge: Modify the currying function to handle multiple placeholders, allowing for more complex argument patterns.

function curry(func) {
  return function curried(...args) {
    const placeholder = curry.placeholder;
 
    const hasPlaceholder = args.includes(placeholder);
    const validArgs = args.filter(arg => arg !== placeholder);
    const hasAllArgs = validArgs.length >= func.length;
 
    if (hasAllArgs && !hasPlaceholder) {
      return func.apply(this, args);
    } else {
      return function(...nextArgs) {
        let index = 0;
        const combinedArgs = args.map(arg => arg === placeholder && nextArgs[index] !== undefined ? nextArgs[index++] : arg).concat(nextArgs.slice(index));
        return curried.apply(this, combinedArgs);
      };
    }
  };
}
 
curry.placeholder = '_';
 
// Example usage with multiple placeholders
function add(a, b, c, d) {
  return a + b + c + d;
}
 
const curriedAdd = curry(add);
 
console.log(curriedAdd(1)('_', 3, '_')(2)('_')(4)); // Output: 10
console.log(curriedAdd('_', 2)('_', 4)(1, '_')(3)); // Output: 10

In this challenge:

  • Enhance the currying function to handle multiple placeholders, allowing arguments to be provided in any order and combination.

AI InterviewPrep

Generate interview questions tailored to your background! Includes behavioral, technical, and job-specific questions based on your resume and job descriptions.

Resume Analyzer

Our AI-powered tool reviews your resume, analyzing job descriptions to highlight essential skills and keywords missing from your resume.