introduction
Let’s take the addition of two numbers as an example to explain in progress.
We usually write a function like this to find the value of the sum of two numbers:
function sum(a,b){ (a+b) } sum(1,2)
There is no problem with writing this way!
But what? Problems will always arise in development, and the product manager needs to add another value, the requirement is: add three numbers;
Generally speaking, at the first time, just add another parameter on the original basis;
So, after modification, it looks like this:
function sum(a,b,c){ (a+b+c) } sum(1,2,3)
Q: Is there any problem with writing like this? ?
Answer: It’s so wrong!
This change violates both the "opening and closing principle" and the "single responsibility principle".
For those who are not familiar with the design principles, a brief explanation:
- What is the "opening and closing principle"? That is: in programming, we should avoid directly modifying functions, classes or modules as much as possible, but instead expand them on the original basis;
- What is the "single responsibility principle"? That is: each function, class or module should only be responsible for a single function;
First, we modified the argument transmission and internal calls of the sum function ⇒ which violates the "open and shutdown principle"
Secondly, the sum function is only responsible for the addition of two numbers. After modification, it is responsible for the addition of three numbers. The responsibilities have changed ⇒ This violates the "single responsibility principle";
If written formally according to single responsibility, it should be:
// Responsible for adding two numbersfunction sum2(a,b){ (a+b) } // Responsible for adding three numbersfunction sum3(a,b,c){ (a+b+c) }
In fact, it is impossible to write this way, because if there are ten thousand numbers added together, you have to write ten thousand functions.
And there is only one addition! ! No matter how many values you want to add in the end, you always need to add one.
So, we imagine whether we can write a function like this: its function is to "add", and I will add a few parameters and a few.
// Responsible for "addition",function addCurry(){ ... ... ... } addCurry(1)(2) // Add two numbersaddCurry(1)(2)(3) // Add up three numbers... addCurry(1)(2)(3)...(n) // n numbers add up
That's right, this function is: Curry! ! (Or it is called Currying, and this idea is called Currying, and Bengua believes that there is no need to define it too hard here)
Next, let’s try step by step, how will it be composed?
In order to achieve the purpose of adding one to one, that is, storing parameters, let’s think about what other magic weapons are there?
That's right, JS mystery: closure!
In fact, Bengua often wonders, what is the ultimate secret of closure? Finally, it is understood as 4 big golden words: delay processing!
What's the meaning? A brief explanation:
function directHandle(a,b){ ("Directly handle",a,b) } directHandle(111,222) // Direct processing 111 222function delayHandle(a){ return function(b){ ("Delay processing",a,b) } } delayHandle(111) // ƒ (b){ // ("Delay processing",a,b)// }
As abovedelayHandle(111)
Not likedirectHandle(111,222)
Print the value directly, but return a function firstf(b)
;111 was also temporarily preserved,delayHandle(111)(222)
, then the same output is obtained. This is: the idea of delay processing.
Another sentence:
Delay processing is the essence of functional programming. On the premise that it cannot be guaranteed that each function is a pure function, processing can be done at the end of the pipeline to minimize side effects. That is, Monad thought, not to be expanded here.
Back to the point, we borrowed closures to implement the initial version of Curry:
// Add two numbersfunction addCurry(a){ return function(b){ (a+b) } } addCurry(1)(2) // Add up three numbersfunction addCurry(a){ return function(b){ return function(c){ (a+b+c) } } } addCurry(1)(2)(3)
When writing two closures, you are smart and you will understand. If you keep writing like this, isn’t it just recursion? !
So, we know that when the parameters are n, recursion n-1 times is requiredreturn function
Therefore, addCurry is written as follows:
let arr = [] function addCurry() { let arg = (arguments); // Recursively get subsequent parameters arr = (arg); if ( === 0) { // If the parameter is empty, then the recursion ends return ((a,b)=>{return a+b}) //Sum } else { return addCurry; } } addCurry(1)(2)(3)()
OK, at this point, the task is done! !
The above is explained in the simplest code - Why do I say: Curry == closure + recursion?
Curry is a kind of thought, and the addCurry above can be said to be the simplest practice. In functional programming, Curry shines even more, such as compose(fn1)(fn2)(fn3)…(fnN)(args) and so on.
If someone asks you about Curryhua in the future, you can answer this direction. . .
The above is the detailed explanation of the principle of closure combination recursion equals Currying. For more information about closure combination recurrying, please pay attention to my other related articles!