The curry in JS (currying)

Source: Internet
Author: User

What is curry/curry?

Curry source and mathematician Haskell Curry's name (the programming language Haskell is also named after his name).

Curry is also often called partial evaluation, the meaning is to give the function step by pass parameters, each pass the parameter after the partial application of parameters, and return a more specific function to accept the remaining parameters, which can be nested in a multi-layer such a partial parameter function, until the final result is returned.
Therefore, the process of curry is to gradually pass the parameters, gradually reduce the scope of application of the function, and gradually solve the process.

Curry a summation function

Let's look at a simple example in terms of step-down evaluation

varConcat3words =function(A, B, c) {returna+b+c;};varConcat3wordscurrying =function(a) {return function(b) {return function(c) {returna+b+C;    }; };}; Console.log (Concat3words ("foo", "Bar", "Baza"));//Foo Bar BazaConsole.log (concat3wordscurrying ("foo"));//[Function]Console.log (concat3wordscurrying ("foo") ("Bar") ("Baza");//Foo Bar Baza

As you can see, concat3wordscurrying ("foo") is a function, each call returns a new function that takes another call, and then returns a new function until the result is returned, the distribution is solved, and the layer is progressive. (PS: The characteristics of closures are used here)

So now we take a step further, if the request can be passed more than 3 parameters, you can pass any number of parameters, when the parameter is not passed the output results?

Let's start with a common implementation:

var function (items) {    return items.reduce (A,b) {        return A + b    }); Console.log (Add ([1,2,3,4]));

But if you need to multiply each number by 10, then:

var function (items,multi) {    return items.map (function  (item) {        return Item *multi;    }). Reduce (function  (A, b) {        return A + b    }); Console.log (Add ([1, 2, 3, 4],10));

Fortunately there are map and reduce functions, if according to this pattern, now to add 1 per item, and then summarize, then we need to change the function in map.

Here's a look at the curry implementation:

varAdder =function () {    var_args = []; return function () {        if(Arguments.length = = 0) {            return_args.reduce (function(A, b) {returnA +b;        });        } [].push.apply (_args, [].slice.call (arguments)); returnArguments.callee;    }}; varsum =adder (); Console.log (sum); //Functionsum (100,200) (300);//flexible invocation, one or more arguments can be entered in a single call, and chained calls are supportedSUM (400); Console.log (sum ()); //1000 (plus total calculation)

The above adder is a function of the Gerty, it returns a new function, the new function receives a sub-batch to accept the new parameters, deferred to the last calculation.

The common curry function

A more typical curry would encapsulate the last calculation into a function, and then pass this function as a parameter into the Curry function, which is clear and flexible.
For example, with each item multiplied by 10, we can pass the handler function as a parameter:

varcurrying =function(FN) {var_args = []; return function () {        if(Arguments.length = = 0) {            returnFn.apply ( This, _args);        } Array.prototype.push.apply (_args, [].slice.call (arguments)); returnArguments.callee; }};varMulti=function () {    varTotal = 0;  for(vari = 0, C; c = arguments[i++];) { Total+=C; }    returnTotal ;};varsum =currying (multi); SUM (100,200) (300); sum (400); Console.log (sum ()); //1000 (true calculation when blank call)

This sum = currying (multi), the call is very clear, the use of the effect is brilliant, for example, to accumulate multiple values, you can use multiple values as a parameter sum (three-way), can also support chained calls, SUM (1) (2) (3)

The role of Curry
    • Deferred calculation. The above example has been shown to be very low.
    • Parameter multiplexing. When the same function is called multiple times and the parameters passed are overwhelmingly the same, then the function may be a good candidate for the curry.
    • Dynamically create functions. This can be done after the partial calculation of the results, on this basis, the dynamic generation of new functions to deal with the subsequent business, thus omitting the repeated calculation. Alternatively, you can dynamically create a new function by using a subset of the parameters that will be passed into the calling function, which is applied to the function, and the new function saves the repeated arguments (which you do not have to pass each time). For example, the event browser adds an auxiliary method for the event:
var function (EL, type, FN, capture) {     if  (window.addeventlistener) {         function(e) {             Fn.call (el, E);         }, capture);      Else if (window.attachevent) {         el.attachevent (function(e) {             fn.call (el, E);         });  };

Every time you add event handling, you have to do it again. If...else ..., in fact, in a browser as long as a single decision can be, based on the results of a decision after the dynamic generation of new functions, you do not have to recalculate.

varAddevent = (function(){   if(window.addeventlistener) {return function(el, Stype, FN, capture) {El.addeventlistener (stype,function(e) {Fn.call (EL, E);       }, (capture));   }; } Else if(window.attachevent) {return function(el, Stype, FN, capture) {el.attachevent ("On" + Stype,function(e) {Fn.call (EL, E);       });   }; }})();

This example, the first time if...else ... After judging, a partial calculation is completed, and a new function is created dynamically to handle the parameters passed in later, which is a typical curry.

Function.prototype.bind method is also the application of curry

Unlike the Call/apply method, the Bind method sets the first parameter to the context of the function execution, and the other parameters are passed to the calling method in turn (the body of the function does not execute itself, can be seen as deferred execution), and the dynamic creation returns a new function, which is in line with the curry feature.

var foo = {x:888}; var function () {    Console.log (this. x);}. Bind (foo);                // bind Bar ();                     // 888

Unlike the Call/apply method, the Bind method sets the first parameter to the context of the function execution, and the other parameters are passed to the calling method in turn (the body of the function does not execute itself, can be seen as deferred execution), and the dynamic creation returns a new function, which is in line with the curry feature.

var foo = {x:888}; var function () {    Console.log (this. x);}. Bind (foo);                // bind Bar ();                     // 888

The following is a simulation of the BIND function, Testbind creates and returns a new function, and in the new function binds the function that is actually executing the business to the context in which the argument was passed, deferred execution.

function (scope) {    varthis;                    //     returnfunction  () {        return  fn.apply (scope);    }};  var testbindbar = Bar.testbind (foo);  // bind foo, defer execution of Console.log (Testbindbar);             // function (visible, BIND returns a new function for deferred execution)

It is important to note the understanding of this in prototype.

Instance

Example 1:

varcurrying =function(FN) {//FN refers to the way officials digest their wives.    varargs = [].slice.call (arguments, 1); //args refers to the legal wife.    return function() {        //already have a wife and a new wife to make a whole, easy to control        varNewargs =Args.concat ([].slice.call (arguments)); //These wives use FN as a means to digest, complete the feat of Wei Xiaobao predecessors and return        returnFn.apply (NULL, Newargs); };};//How to get the 7 wives ' test done by an official.//get a legal wifevarGetwife = currying (function() {    varAllwife =[].slice.call (arguments); //Allwife is the wife of all the wives, including the sneak in.Console.log (Allwife.join (";"));}, "Legal wife.");//get 6 other wivesGetwife ("Big Wife", "Little Wife", "Qiao Wife", "unruly wife", "Good Wife", "door to wife");//change a wife .Getwife ("Beyond Wei Xiaobao's wife");

Results:

A lawful wife , a wife, a wife, a wife, a unruly wife, a wife who is a legitimate wife, a wife beyond Wei Xiaobao.

Example 2:

varCurryweight =function(FN) {var_fishweight = []; return function() {        if(Arguments.length = = 0) {            returnFn.apply (NULL, _fishweight); } Else{_fishweight=_fishweight.concat ([].slice.call (arguments)); }    }};varFishweight = 0;varAddweight = Curryweight (function() {    vari=0; Len =arguments.length;  for(i; i<len; i+=1) {Fishweight+=Arguments[i]; }}); Addweight (2.3); Addweight (6.5); Addweight (1.2); Addweight (2.5); Addweight (); //Here's the calculation .Console.log (fishweight); //12.5
Reference address

A brief analysis of function currying currying in JavaScript
The curry in JS (currying)

The curry in JS (currying)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.