Currying
On this page
JavaScript Currying
In JavaScript, there exists an advanced technique of working with functions. It is called carrying. However, it is used not only in JavaScript but also in other programming languages. (在JavaScript中,存在使用函数的高级技术。它被称为携带。然而,它不仅在JavaScript中使用,而且在其他编程语言中也使用。)
Generally, it is a transformation of functions.So, it translates a function from callable likef(a, b, c) to f(a)(b)(c) . (一般来说,它是函数的转换。因此,它将函数从可调用的likef (a, b, c)转换为f (a) (b) (c)。)
A function can’t be called by currying. What it does is merely transforming. (不能通过currying调用函数。它所做的只是转变。)
For a better perception, let’s start at an example:
function curry(fn) { // curry(fn) does transforms curry
return function (a) {
return function (b) {
return fn(a, b);
};
};
}
function sum(a, b) {
return a + b;
}
let currySum = curry(sum);
console.log(currySum(10)(20)); // 30
In the example above, there is a helper function curry(fn) that implements currying for a two-argument f. (在上面的示例中,有一个辅助函数curry (fn) ,它实现了两个参数f的curry。)
It’s a simple performance with two wrappers. A wrapper function(a) is the result of curry(func). Once you call curySum(1), the argument is saved in the Lexical Environment. A new wrapper function(b) is returned. Afterward, it is called with argument 2, passing the call to sum . (这是一个简单的性能与两个包装。包装函数(a)是curry (func)的结果。调用curySum (1)后,参数将保存在词法环境中。返回一个新的包装函数(b)。之后,使用参数2调用它,将调用传递给sum。)
Here is a more complex example:
function sum(a, b) {
return a + b;
}
let currySum = _.curry(sum); // using _.curry from lodash library
alert(currySum(10, 20)); // 30, still callable normally
alert(currySum(10)(20)); // 30, called partially
The purpose of Currying
The purpose of Currying (咖喱的目的)
To understand the main purpose of currying, we should check out a real-life example:
function log(date, importance, message) {
console.log(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}
Here we have log(date, importance, message), which formats and outputs information. (在这里,我们有日志(日期、重要性、消息) ,用于格式化和输出信息。)
Currying it will look like this:
logs = _.curry(log);
So, the log will work properly after that:
log(new Date(), "DEBUG", "debug"); // log(a, b, c)
In the curried form it will also work:
log(new Date())("DEBUG")("debug"); // log(a)(b)(c)
So, after currying, nothing is lost. Partial functions, also, can be easily generated. (所以,咖喱后,什么都不会丢失。部分函数也可以轻松生成。)
Advanced Currying
Advanced Currying (高级咖喱)
Now let’s get into some details and check out more complicated currying with multi-argument functions. (现在,让我们深入了解一些细节,看看使用多参数函数进行更复杂的柯里化。)
It’s quite brief, as shown below:
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function (...args2) {
return curried.apply(this, args.concat(args2));
}
}
};
}
A usage example will look like this:
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function (...args2) {
return curried.apply(this, args.concat(args2));
}
}
};
}
function sum(a, b, c) {
return a + b + c;
}
let currySum = curry(sum);
console.log(currySum(10, 20, 30)); // 60, still callable normally
console.log(currySum(10)(20, 30)); // 60, currying of 1st arg
console.log(currySum(10)(20)(30)); // 60, full currying
The wrapper curried will become the result of curry(fn):
// fn is function to transform
function curried(...args) {
if (args.length >= fn.length) { // (1)
return fn.apply(this, args);
} else {
return function pass(...args2) { // (2)
return curried.apply(this, args.concat(args2));
}
}
};
Running it will lead to two if execution branches. The first is calling now. In case the passed args count is similar to the original function includes in its definition or longer, then the call should be passed to it. The second is getting a partial. In another way, the fn is not called yet. Another pass is returned. It can re-apply curried providing previous arguments with the new ones. Afterward, on a new call, either a new partial or the result will be received. (如果执行分支,运行它将导致两个。第一个是现在打电话。如果传递的args计数与其定义中的原始函数include相似或更长,则应将调用传递给它。第二个是得到部分。换句话说, fn还没有被调用。返回另一个通行证。它可以重新应用curried ,提供以前的参数和新的参数。之后,在新的调用中,将收到新的部分或结果。)
It is essential to note that for the currying, a fixed number of arguments is required. So, a function using rest parameters f(…args) like will not be curried like that. (需要注意的是,对于currying ,需要固定数量的参数。因此,使用rest参数f (… args)的函数将不会像这样被curry。)
Summary
Summary (概要)
In JavaScript, currying represents a transform, which turns the callable f(a,b,c) to f(a)(b)(c) . Normally, JavaScript implementations keep the function callable, as well as return the partial, once the argument counts are less than needed. Getting partials is also easy with currying. (在JavaScript中, currying表示一种变换,它将可调用的f (a, b, c)转换为f (a) (b) (c)。 通常, JavaScript实现会保持函数可调用,并在参数计数小于需要时返回partial。 用咖喱烹饪也可以轻松获得份量。)