The curry in JS and the realization of the ingenious automatic curry

Source: Internet
Author: User

First, what is the curry?

In computer science, currying is a technique that transforms a function that accepts multiple parameters into a function that takes a single parameter (the first parameter of the original function) and returns a new function that takes the remaining parameters and returns the result . This technique was named by Christopher Strachey, a logic home Curry, although it was invented by Moses Schnfinkel and Gottlob Frege.

Theory looks big on the head? It doesn't matter, look at the code first:

Second, the application of curry

Suppose we need to implement a function that does some sort of processing of list elements, such as adding one to each element in the list, it's easy to think of:

const list = [01231);

It's easy, right? What if we add 2 again?

const list = [012312 );

It looks a little inefficient, and the processing function encapsulates it?

However, the callback function of map only accepts the current element elem This parameter, it seems that there is no way to encapsulate. You might think that it would be nice to get a partially configured function, such as:

// plus returns a partially configured function const PLUS1 = Plus (1); const PLUS2 = Plus (2);p lus1 (5//  = 6plus2 (7  //  = 9

To pass such a function into a map:

const list = [0123//  = = [1, 2, 3, 4]//< /c9> = [2, 3, 4, 5]

Isn't it great? This way, no matter how much, only need List.map (plus (x)) is good, the perfect package, readability greatly improved!

But here's the question: How is this plus function going to be implemented? This is where currying can be useful:

Three, the function of curry

// the original addition function function Origplus (A, b) {  return a + b;} // the plus function after the curry function Plus (a) {  return  function (b) {    return a + B;  }}  //  ES6 The wording consta = B + A + B;

As you can see, the Curry plus function first takes a parameter A and then returns a function that takes a parameter B, and because of the closure, the returned function can access the parameter a of the parent function.

So for example: const PLUS2 = Plus (2), which is equivalent to function Plus2 (b) {return 2 + B;}, which enables partial configuration.

  In layman's parlance, the process of configuring a multi-parameter function is a partial configuration, and each step returns a partially configured function that accepts a single parameter . Some extreme situations may require several times to partially configure a function, such as adding multiple times:

Multiplus (1) (2) (3//  = 6

That's a weird look, isn't it? But if you are familiar with JS's functional programming, this will be the norm.

The ingenious realization of automatic curry in JS

Curry (currying) is a very important part of functional programming, and many functional languages (eg. Haskell) will automatically curry the function by default. However, JS does not, so we need to implement the function of automatic curry. Look at the code first:

//ES5function Curry (FN) {function _c (restnum, argslist) {returnRestnum = = =0?fn.apply (NULL, Argslist): function (x) {return_c (Restnum-1, Argslist.concat (x));  }; }  return_c (Fn.length, []);}//ES6ConstCurry = FN = = {  Const_c = (Restnum, argslist) = Restnum = = =0?fn (... argslist): x= _c (Restnum-1, [... argslist, x]); return_c (Fn.length, []);}/***************** using *********************/varPlus =Curry (function (A, b) {returnA +b;});//ES6Constplus = Curry ((A, B) + A +b);p LUs (2)(4);//= 6

This will enable the automatic curry! Let's start with a little bit of thought:

1. Demand Analysis

We need a curry function, which takes a function to be gerty as a parameter, returns a function to receive a parameter, the received parameter is placed in a list, and when the number of arguments is sufficient, the original function is executed and the result is returned.

2. Realization method

Simple thinking can be known that the number of steps to curry partial configuration function equals the number of FN parameters, that is, two parameters of the plus function needs to be partially configured in two steps. the number of arguments for a function can be obtained by Fn.length .

The general idea is that every time you pass the argument, you put the parameter into a parameter list argslist, and if there are no arguments to pass, call fn.apply (null, argslist) to execute the original function. To achieve this, we need an internal judgment function _c (Restnum, argslist), the function accepts two parameters, one is the number of remaining arguments restnum, and the other is the list of obtained parameters Argslist;_c function is to determine if there are no parameters passed in, when When Restnum is zero, it is time to execute the original function and return the result by fn.apply (null, argslist). If there are arguments that need to be passed, that is, Restnum is not zero, you need to return a single-argument function

function (x) {  return1, argslist.  Concat(x));}

  To continue receiving parameters. Here a tail recursion is formed, after the function takes a parameter, the remainder requires the number of arguments restnum minus one, and the new parameter x is added to the argslist and passed in to the _c for recursive invocation. The result is that when the number of arguments is insufficient, the single-argument function that receives the new parameter is returned, and when the argument is sufficient, the original function is called and returned.

Now look again.

function Curry (FN) {  function _c (restnum, argslist) {    return0 ?       Fn.apply (null, argslist):      function (x) {        return1, Argslist.concat (x));}      ;  }   return // recursive start }

Is it starting to clear up?

ES6 's way of writing because of the use of syntactic sugars such as array deconstruction and arrow functions , it seems a lot leaner, but the idea is the same

// ES6 const Curry = fn + =  {const0 ?      1 , [... argslist, x]);   return _c (Fn.length, []);}

3. Comparison with other methods

There is also a common method for everyone:

function Curry (FN) {ConstLen =fn.length; returnfunction judge (... args1) {returnArgs1.length >= len?fn (... args1): function (... args2) {returnJudge (...    [... args1, ... args2]); }  }}//Use the arrow functionsConstCurry = FN = = {  ConstLen =fn.length; ConstJudge = (... args1) = Args1.length >= len?fn (... args1): (... args2)=Judge (...  [... args1, ... args2]); returnjudge;}

Compared with the method mentioned earlier in this article, there are two problems with this method:

(1) The Deconstruction of dependent ES6 (in the function parameter ... args1 with ... args2);

(2) slightly worse performance.

4, performance issues

Do a test:

Console.time ("Curry"); const plus = Curry ((A, B, C, D, e) = + A + B + C + D + e);p LUs (1) (2) (3) (
    
     4) (
     5
     ); Console.timeend (
     "
     Curry
     ");
    

The method mentioned in this article takes about 0.550ms, and other methods take about 2.309ms of time

The bad guess is the reason for the closure. Because the access to the closure is more cost-intensive, and this approach forms two closures: FN and Len, the previously mentioned method only forms the FN one closure, so this tiny gap is created.

The curry in JS and the ingenious automatic curry implementation

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.