# What is Corellian?

## Official statement

In computer science,Corellian(English:`Currying`), and translated into`Karenization`Or`Gallicization`, is a technique that transforms a function that accepts multiple parameters into a function that accepts a single parameter (the first parameter of the original function), and returns a new function that accepts the remaining parameters and returns the result. This technology consists of`Christopher strachey`As a logician`haskell brooks curry`Named, although it is`Moses Schönfinkel`And`Gottlob Frege invented it`.

Intuitively, Corellian claimedIf you fix some parameters, you will get a function that accepts the remaining parameters..
In theoretical computer science, Corellian provides a simple theoretical model, such as one that accepts only a single parameter`lambda`In calculus, the method of studying functions with multiple parameters is studied.
The duality of the function coritization is`Uncurrying`, a method of implementing multi-parameter functions using anonymous single-parameter functions.

## Convenient understanding

The concept of Currying is actually very simple, passing only a part of the function’s parameters to call it, allowing it to return a function to process the remaining parameters.

If we need to implement a function that sums three numbers:

``````function add(x, y, z) {
return x + y + z;
}
``````var add = function(x) {
return function(y) {
return function(z) {
return x + y + z;
}
}
}

Here we define a`add`Function that takes a parameter and returns a new function. call`add`After that, the returned function is remembered by closure`add`The first parameter of the. It is a bit tedious to call it once, but fortunately we can use a special`curry`Help function (`helper function`) makes it easier to define and call such functions.

Use`ES6`The arrow function, we can put the above`add`This is achieved as follows:

``const add = x => y => z => x + y + z;``

It seems much clearer to use the arrow function.

# Partial function?

Let’s look at this function:

``````function ajax(url, data, callback) {
// ..
}``````

There is a scenario in which we need to initiate for multiple different interfaces`HTTP`There are two ways to request:

• On call`ajax()`Function, the global is passed in`URL`Constant.
• Create an already preset`URL`A function reference to an argument.

Let’s create a new function that is still initiated internally`ajax()`Request, in addition, while waiting to receive the other two arguments, we manually`ajax()`The first argument is set to what you care about`API`Address.

For the first approach, we may generate the following call methods:

``````function ajaxTest1(data, callback) {
ajax('http://www.test.com/test1', data, callback);
}

function ajaxTest2(data, callback) {
ajax('http://www.test.com/test2', data, callback);
}``````

For these two similar functions, we can also extract the following patterns:

``````function beginTest(callback) {
ajaxTest1({
data: GLOBAL_TEST_1,
}, callback);
}``````

I’m sure you’ve seen a pattern where we call functions in the field (`function call-site`), the argument is applied (`apply`) in formal parameters. As you can see, we applied only part of the arguments at the beginning-specifically, we applied the arguments to`URL`Formal parameters-the remaining arguments will be applied later.

The above concept isPartial functionThe definition of partial function is a process of reducing the number of function parameters. The number of parameters here refers to the number of formal parameters that you want to pass in. We passed`ajaxTest1()`Put the original function`ajax()`The number of parameters for is from`3`This number has been reduced to`2`A.

We define a`partial()`Functions:

``````function partial(fn, ...presetArgs) {
return function partiallyApplied(...laterArgs) {
return fn(...presetArgs, ...laterArgs);
}
}``````

`partial()`Function reception`fn`Parameter to represent the arguments that we are biased to apply (`partially apply`) function. And then,`fn`After the formal parameters,`presetArgs`The array collects the arguments passed in later and saves them for later use.

We created and`return`A new internal function was created (for clarity, we named it`partiallyApplied(..)`In this function,`laterArgs`The array collected all the arguments.

The arrow function is more concise:

``````var partial =
(fn, ...presetArgs) =>
(...laterArgs) =>
fn(...presetArgs, ...laterArgs);``````

Using this pattern of partial functions, we refactored the previous code:

``````function ajax(url, data, callback) {
// ..
}

var ajaxTest1 = partial(ajax, 'http://www.test.com/test1');
var ajaxTest2 = partial(ajax, 'http://www.test.com/test1');``````

Think again`beginTest()`Function, we use the`partial()`How should we reconstruct it?

``````function ajax(url, data, callback) {
// ..
}

// 版本1
var beginTest = partial(ajax, 'http://www.test.com/test1', {
data: GLOBAL_TEST_1,
});

// 版本2
var ajaxTest1 = partial(ajax, 'http://www.test.com/test1');
var beginTest = partial(ajaxTest1, {
data: GLOBAL_TEST_1,
});``````

# Pass one at a time

I believe you have seen the advantages of version 2 over version 1 in the above examples. Yes, Corelliation is the process of converting a function with multiple parameters into one function at a time. Each time a function is called, it accepts only one parameter and returns a function until all parameters are passed.

The process of converting a function that takes multiple arguments into a function that takes them one at a time.

Each time the function is called it only accepts one argument and returns a function that takes one argument until all arguments are passed.

Let’s say we’ve already created a Corellian version of the`ajax()`Function`curriedAjax()`

``````curriedAjax('http://www.test.com/test1')
({
data: GLOBAL_TEST_1,
})
(function callback(data) {
// dosomething
});``````

We will separate the three calls, which may help us understand the whole process:

``````var ajaxTest1 = curriedAjax('http://www.test.com/test1');

var beginTest = ajaxTest1({
data: GLOBAL_TEST_1,
});

var ajaxCallback = beginTest(function callback(data) {
// dosomething
});``````

# The realization of Corellization

So, how do we implement an automatic Coriolis function?

``````var currying = function(fn) {
var args = [];

return function() {
if (arguments.length === 0) {
return fn.apply(this, args); // 没传参数时，调用这个函数
} else {
[].push.apply(args, arguments); // 传入了参数，把参数保存下来
return arguments.callee; // 返回这个函数的引用
}
}
}``````

Call the above`currying()`Functions:

``````var cost = (function() {
var money = 0;
return function() {
for (var i = 0; i < arguments.length; i++) {
money += arguments[i];
}
return money;
}
})();

var cost = currying(cost);

cost(100); // 传入了参数，不真正求值
cost(200); // 传入了参数，不真正求值
cost(300); // 传入了参数，不真正求值

console.log(cost()); // 求值并且输出600``````

The above function is my previous oneJavaScript Design Patterns and Development Practice Closures and Higher Order Functions of Reading NotesWritten by`currying`Version, now after careful consideration, we find that there are still some problems.

When we use kriging, we should pay attention to the case of parameters that are pre-passed for functions at the same time.

Therefore, change the above Coriolis function as follows:

``````var currying = function(fn) {
var args = Array.prototype.slice.call(arguments, 1);

return function() {
if (arguments.length === 0) {
return fn.apply(this, args); // 没传参数时，调用这个函数
} else {
[].push.apply(args, arguments); // 传入了参数，把参数保存下来
return arguments.callee; // 返回这个函数的引用
}
}
}``````

Use examples:

``````var cost = (function() {
var money = 0;
return function() {
for (var i = 0; i < arguments.length; i++) {
money += arguments[i];
}
return money;
}
})();

var cost = currying(cost, 100);
cost(200); // 传入了参数，不真正求值
cost(300); // 传入了参数，不真正求值

console.log(cost()); // 求值并且输出600``````

You may feel that you have to call without parameters at the end of each call.`cost()`Function is more troublesome, and in the`cost()`Functions to be used`arguments`The parameters do not meet your expectations. We know that all functions have one`length`Property, indicating the number of parameters the function expects to accept. Therefore, we can make full use of this characteristic of pre-transmitted parameters.

Learn frommqyqingfeng

``````function sub_curry(fn) {
var args = [].slice.call(arguments, 1);
return function() {
return fn.apply(this, args.concat([].slice.call(arguments)));
};
}

function curry(fn, length) {

length = length || fn.length;

var slice = Array.prototype.slice;

return function() {
if (arguments.length < length) {
var combined = [fn].concat(slice.call(arguments));
return curry(sub_curry.apply(this, combined), length - arguments.length);
} else {
return fn.apply(this, arguments);
}
};
}``````

In the above function, in currying’s return function, each time we put`arguments.length`And`fn.length`For comparison, once`arguments.length`Reached`fn.length`The number of, we will go to call`fn`(`return fn.apply(this, arguments);`)

Verification:

``````var fn = curry(function(a, b, c) {
return [a, b, c];
});

fn("a", "b", "c") // ["a", "b", "c"]
fn("a", "b")("c") // ["a", "b", "c"]
fn("a")("b")("c") // ["a", "b", "c"]
fn("a")("b", "c") // ["a", "b", "c"]``````

# Implementation of bind method

The use of coriolis can be easily borrowed.`call()`Or ..`apply()`Realization`bind()`Method of`polyfill`.

``````Function.prototype.bind = Function.prototype.bind || function(context) {
var me = this;
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return me.apply(contenxt, finalArgs);
}
}``````

Some of the problems with the above functions are that they are not compatible with constructors. We judge whether this function passes or not by judging the prototype attribute of the object pointed to by this`new`Called as a constructor to make the above`bind`Methods are compatible with constructors.

Function.prototype.bind() by MDNAs follows:

The binding function is suitable for using the new operator new to construct a new instance created by the objective function. When a binding function is used to construct a value, the originally provided this is ignored. However, those parameters originally provided will still be prepended to the constructor call.

This isJavaScript Web rich application development based on MVCThe`bind()`Method implementation:

``````Function.prototype.bind = function(oThis) {
if (typeof this !== "function") {
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}

var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(
this instanceof fNOP && oThis ? this : oThis || window,
aArgs.concat(Array.prototype.slice.call(arguments))
);
};

fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();

return fBound;
};``````

# Uncurring

You may encounter a situation where you get a corialized function and want it to be a corialized version of the previous one, which is essentially a similar one.`f(1)(2)(3)`The function of returns to similar`g(1,2,3)`The function of.

The following is simple`uncurrying`The implementation of:

``````function uncurrying(fn) {
return function(...args) {
var ret = fn;

for (let i = 0; i < args.length; i++) {
ret = ret(args[i]); // 反复调用currying版本的函数
}

return ret; // 返回结果
};
}``````

Note, don’t think that the functions after uncurrying are exactly the same as the functions before currying, they just behave similarly!

``````var currying = function(fn) {
var args = Array.prototype.slice.call(arguments, 1);

return function() {
if (arguments.length === 0) {
return fn.apply(this, args); // 没传参数时，调用这个函数
} else {
[].push.apply(args, arguments); // 传入了参数，把参数保存下来
return arguments.callee; // 返回这个函数的引用
}
}
}

function uncurrying(fn) {
return function(...args) {
var ret = fn;

for (let i = 0; i < args.length; i++) {
ret = ret(args[i]); // 反复调用currying版本的函数
}

return ret; // 返回结果
};
}

var cost = (function() {
var money = 0;
return function() {
for (var i = 0; i < arguments.length; i++) {
money += arguments[i];
}
return money;
}
})();

var curryingCost = currying(cost);
var uncurryingCost = uncurrying(curryingCost);
console.log(uncurryingCost(100, 200, 300)()); // 600``````

# What’s the use of coriolis or partial functions?

Whether it’s coriolis or partial application, we can pass values partially, while traditional function calls need to determine all arguments in advance. If you get only part of the arguments in one part of the code and then determine another part of the arguments in another part of the code, then corialization and partial application can come in handy.

Another thing that best embodies the Coriolis application is that when functions have only one formal parameter, we can easily combine them (`Single responsibility principle`）。 Therefore, if a function finally needs three arguments, it will become a function that needs three calls after it is coritized, and each call needs one argument. When we combine functions, this unit function form will make our processing simpler.

Summarized, mainly for the following common three purposes:

• Delay calculation
• Parameter reuse
• Dynamically generated function