For every programmer, writing reusable code is essential. Each person has their own ways of achieving this, such as creating libraries of useful code snippets. But in this article, let's focus more on a micro-level approach, at the function level.
The concept of a curry function is quite simple - it is a regular JavaScript function that takes multiple arguments as a series of single-argument functions. For example:
function sum(a) {
return function add(b) {
return a + b;
}
}
const add1 = sum(1);
const result = add1(2);
console.log(result); // 3;
// Alternatively, we can write it more concisely as:
const result = sum(1)(2);
console.log(result); // 3
Oh, the syntax seems unfamiliar, doesn't it? So what benefits does it bring?
There are two things that curry functions can bring:
Let me provide examples to clarify these two points.
In the first example, I have an array of objects with id
and name
, and I want to extract only the id
:
const objects = [{ id: 1, name: "A" }, { id: 2, name: "B" }, { id: 3, name: "C" }];
const ids = objects.map(function (o) { return o.id; });
It looks simple, right? But there is a problem with function (o) { return o.id; }
- it works, but it can be better. Let's improve it:
function get(attr) {
return function getAttr(obj) {
return obj[attr];
}
}
const ids = objects.map(get("id"));
get
is a curry function. It takes an attr
to serve the purpose of extracting a specific attribute and an obj
as the object to be extracted.
You may find the syntax in ids
a bit confusing, so let's recall the map
function in JavaScript:
Array.map(function (i) { return i; });
.map
takes a function as a parameter, which has access to each element in the array for processing.
In other words, this is actually what ids
does:
const ids = objects.map(function (o) { return get("id")(o); });
Now do you understand? So here's a question for you: if I want to reuse the function that extracts id
from objects
, how would I do it? Is it like this:
function getIds(objs) {
return objects.map(get("id"));
}
getIds(objects);
It seems to work, but it can still be improved. Why don't we apply curry function to create a function called "map" that loops through the elements in an array?
function map(func) {
return function exec(value) {
return value.map(func);
}
}
const getIds = map(get("id"));
getIds(objects);
Here, I can see that if basic functions are curried, I can easily create a new function that performs a different functionality from them. And another thing is that the code is written in a very readable manner, making it clear what it does at first glance.
One advantage of curry functions is that they allow your code to focus more on the specific functionality rather than being a regular function. In the examples above, using curry functions makes the code look more understandable:
fetchData()
.then(JSON.parse)
.then(function(data){ return data.posts })
.then(function(posts){
return posts.map(function(post){ return post.title })
});
You may have a different way to write it, but in this case, I want to emphasize that using curry functions will make the code look more understandable:
fetchData()
.then(JSON.parse)
.then(get("posts")
.then(map(get("id")));
Thanks to the benefits of curry functions, there are quite a few supporting libraries such as the curry and curry functions in Ramda, a famous library for functional programming.
Curry functions are a way to "play" with functions, making it easier to understand and utilize the benefits they bring. If you find it fascinating, try applying it to your next project starting from now.
5 profound lessons
Every product comes with stories. The success of others is an inspiration for many to follow. 5 lessons learned have changed me forever. How about you? Click now!
Subscribe to receive new article notifications
Comments (0)