Master Advanced Javascript: Function Currying and Partial Application for Code Reuse

Vamsi Krishna Kodimela
Angular Simplified
Published in
4 min readJan 4, 2024

--

Every one of us might have come across functions that accept a lot of parameters. It looks great while defining but using it is a nightmare. One more issue with this is that just to change one value in these parameters we’ve to rerun the function. It will cause performance bailouts when it comes to large-scale applications.

In this article let’s explore the concepts of currying and partial application to define powerful functions that help us in overcoming these issues.

Function Currying

Just Imagine function as a recipe to cook a sandwich. We need to add ingredients like tomatoes, onions, cheese, pepper,… If we add all these together, it’ll work.

// Method Declaration
function sandwichMaker(
tomatoes,
oninons,
cheese,
pickles,
mustard,
mayo,
keyIngredient
) {
return (
"We're cokking your sandwich: " +
tomatoes +
oninons +
lettuce +
cheese +
pickles +
mustard +
mayo +
keyIngredient
);
}


// Method call
console.log(sandwichMaker(true, true, true, true, true, true, true, "Panner"));

But what about organizing, efficiency, and reusability which will differentiate a master chef from a sue chef? Instead, Let’s use currying to make it more efficient.

Currying transforms a function that takes several arguments into a sequence of functions, each accepting a single argument.

// Method Declaration
function basicIngredients(tomatoes) {
return (
"We're cokking your sandwich: " +
tomatoes +
function (oninons) {
return (
oninons +
function (cheese) {
return (
cheese +
function (pickles) {
return (
pickles +
function (mustard) {
return (
mustard +
function (mayo) {
return (
mayo +
function (keyIngredient) {
return keyIngredient;
}
);
}
);
}
);
}
);
}
);
}
);
}

// Method Invocation
basicIngredients("tomatoes")("oninons")("cheese")("pickles")("mustard")("mayo")("Panner");

This might not make sense for this case but in real time it’ll improve the readability and reusability of the code. Currying lays the foundation of techniques like partial application.

Partial Application

Now our restaurant has two orders to make a Paneer sandwich and a corn sandwich, the whole process is the same except for our key ingredients which of course we’ll add at the last. What if we have a pre-made sandwich that is ready to deliver, all we need to do is add our key ingredient. It’ll save both cost and time. The same is applicable for functions as well. Let’s see how we can define such a which is preprocessed.

The partial Application technique allows you to pre-fill some arguments in a function while keeping the remaining slots open for later use.

const sandwichMix = basicIngredients("tomatoes")("oninons")("cheese")("pickles")("mustard")("mayo");

// Let's cook Panner Sandwich
const pannerSandwich = sandwichMix("Panner");

// Let's cook Corn Sandwich
const cornSandwich = sandwichMix("Corn");

Instead of processing the basic ingredients twice, we processed the function partially, and based on our requirement we’re changing the key ingredient optimizing both cost and time. This technique we’re using here is called Closures.

bind Method

The built-in bind method is a popular tool for partial application.

// Let's cook Tea and Coffee
function teaAndCoffee(milk, isCoffee, sugarCubes) {
return (
"Your " +
(isCoffee ? "Coffee" : "Tea") +
" is ready with " +
milk +
" and " +
sugarCubes +
" sugar cubes."
);
}

// Let's cook Coffee
const coffee = teaAndCoffee.bind(null, "full cream", true);

// Let's cook Tea
const tea = teaAndCoffee.bind(null, "half cream", false);

// Let's cook Coffee with 2 sugar cubes
console.log(coffee(2));

// Let's cook Tea with 1 sugar cubes
console.log(tea(1));

Now, no need to brew your coffee or tea again and again. Just add sugar to your taste.

The advantage of currying and partial application is at any point in time you can use your source function to customize your parameters.

Some advanced techniques that use currying and partial application:

Function Composition: Combine multiple functions to create complex operations. Currying and partial application make this a breeze.

const add= (x)=> (y)=> x+y;
const subtract=(x)=>(y)=>x-y;

// Combining Methods
const applyBoth = (add,sub)=>(x)=>add(sub(x));

// Partial Application
const subtractAndAdd5 = applyBoth(add(5),subtract(5));

// Execution
console.log(subtractAndAdd5(100));

Memoization: Cache function results for performance optimization. Currying and partial application align perfectly with memoization. We can explore memoization in future articles.

function memoize(fn) {
const cache = {};
return (...args) => {
const key = JSON.stringify(args);
return cache[key] || (cache[key] = fn(...args));
};
}

const curriedExpensiveCalc = memoize(x => y => x * y + Math.log(x + y));

--

--