Some thoughts on the curry of JavaScript function

Source: Internet
Author: User

1. Pits of higher order functions

Before learning to curry, let's start by looking at the following piece of code:

var f1 = function (x) {    return F (x);}; F1 (x);

Many students can see that these write is very silly, because the function f1 and f is equivalent, we directly var f1 = f; to the line, there is no need to wrap a layer.

However, the following piece of code may not be able to see the problem:

var getserverstuff = function (callback) {  return Ajaxcall (function (JSON) {    return callback (JSON);  });};

This is a piece of code that I excerpted from the JS Functional Programming Guide, and actually, using the rules above, we can draw a callback function

function (JSON) {return callback (JSON);};

is equivalent, so the function can be reduced to:

var getserverstuff = function (callback) {  return Ajaxcall (callback);};

Continue to simplify:

var getserverstuff = Ajaxcall;

As a result, we find that the long program has been written in white.

Functions can be both parameters and return values, which is an important feature of higher-order functions, but it is easy to step into a hole if you are not careful.

2. Function of curry (curry)

What is the function of curry? The function curry (curry) is simply passed to the function as part of the argument to invoke it, so that it returns a function to handle the remaining arguments. Listen very much, in fact, very simple, in fact, the function of the variable split to call: f(x,y,z) -> f(x)(y)(z) .

For the first example, the following implementation, in order to pass in two parameters, the f1 call method is f1(f,x) .

var f1 = function (f,x) {    return F (x);};

Note that because f it is passed in as a function variable, it f1 becomes a new function.

We're going to f1 change, using closures can be written in the following form, then the f1 invocation becomes f1(f)(x) , and the results are exactly the same. This is the completion f1 of the curry.

var f1 = function (f) {    return function (x) {        return F (x);    }}; var F2 = F1 (f); F2 (x);

In fact, this example is not appropriate, the careful classmate may find, f1 although a new function, but f2 and f is completely equivalent, around the half-day, or around back.

Here's a classic example:

[' One ', ' one ', ' One '].map (parseint)//[, NaN, 3] [' One ', ' one ', ' one '].map (F1 (parseint))//[11, 11, 11]

Due to the parseInt acceptance of two parameters, the direct call will have a conversion problem, referring to the "unwilling to go" article.

var f2 = f1(parseInt), f2 let the parseInt original accept two parameters into a new function that accepts only one parameter, thus solving the problem of the conversion of the binary. We f1 can run the right results after our package.

Some students think that this does not count the application of curry, I think it is OK, you can come together to discuss the students.

3. Function of Curry further thinking

In the example of the previous section, we did not run directly f(x) , but instead treated the function as f a parameter, what would the result be? Let's look at the following example:

Assume that f1 the return function g , g the scope of the function, is xs f g the parameter. In the end we can write the following form:

var f1 = function (f,xs) {    return G.call (xs,f);};

In fact, f1 the alternative g.call(xxx) approach is called anti-curry. For example:

var ForEach = function (xs,f) {    return Array.prototype.forEach.call (xs,f);}; var f = function (x) {console.log (x);}; var xs = {0: ' Peng ', 1: ' Chen ', Length:2};foreach (xs,f);

Anti-curring is to delay the existing fixed parameters or the this context as parameters for future delivery.
It can simplify the function to a great extent, if you have to get used to it.

Put aside the anti-curry, what if we want to currying f1 ?

Using closures, we can write the following form:

var f1 = function (f) {    return function (XS) {        return G.call (xs,f);    }}; var F2 = F1 (f); F2 (XS);

f f1 We can get f2 this new function by passing in.

Only part of the parameter passed to the function is often called a partial call (partial application), which can be used to reduce the template file code (boilerplate).

Of course, f1 the two arguments passed in by a function do not necessarily include functions + non-functions, two are functions, and perhaps two are non-functions.

I personally think that it is not necessary to curry, and unfamiliar classmates may have trouble reading, but it can help us understand the function of JS programming, and more importantly, we will read similar code in the future, do not feel strange. I know the Rough classmate said very well:

Not "curry" is meaningful for functional programming. Instead, functional programming, when used as a class citizen, inevitably produces the use of "curry". So it is not because of "what is the meaning" to appear. Of course, since there is, we can naturally explore how to use this phenomenon.

Practice:

Remove all parameters by local call (partial apply) var Filterqs = function (xs) {  return filter (function (x) {return match (/q/i, x);  }, XS);};/ /These two functions are not the original problem, I added the var filter = function (F,XS) {    return xs.filter (f);}; var match = function (what,x) {    return x.match (what);};

Analysis: filterQs The function is to pass in an array of strings, filter out strings containing ' Q ', and form a new array to return.

We can get the function by the following steps filterQs :

A. filter incoming two parameters, the first is a callback function, the second is an array, and the filter main function is to filter the array based on the callback function. We first filter currying the function:

var filter = function (f) {    return function (XS) {        return xs.filter (f);    }};

B. Second, the filter function passed in the callback function is match , match the main function is to determine whether each string matches what this regular expression. Here we will match also currying:

var match = function (what) {    return function (x) {        return x.match (what);    }}; var match2 = match (/q/i);

Create a matching function match2 to check whether the string contains the letter Q.

C. By match2 combining the incoming filter , a new function is formed:

var Filterqs =  Filter (MATCH2), var xs = [' Q ', ' test1 ', ' test2 '];filterqs (XS);

From this example, we can also realize the power of the function curry. Therefore, currying also has an important function: to encapsulate functions of different functions, using existing functions to form a new function.

4. Recursive invocation of function curry

The function currying also has an interesting form, which is that functions can invoke themselves in closures, similar to the recursive invocation of functions. As shown below:

function Add (seed) {    function RetVal (later) {        return Add (Seed + later);    }    retval.tostring = function () {        return seed;    };    return retVal;} Console.log (Add (1) (2) (3). ToString ()); 6

addThe function returns the closure retVal , which in retVal turn continues to be called, and in the add end we can write add(1)(2)(3)(...) this form of the curry.
As for the answer to this code, the Li Hongxun classmate on the answer is very good:

Each time the Add function is called, the RetValue function is returned, the call to the RetValue function calls the Add function, and then the RetValue function is returned, so the result of calling add must be to return a retvalue function. The Add function is meant only to provide closures, and this similar recursive call generates a new closure each time the add is called.

5. Function combination (compose)

The function combination is done on the basis of the curry:

var compose = function (f,g) {  return function (x) {    return F (g (x));  };}; var f1 = Compose (f,g); F1 (x);

Turn the incoming function into two, returning a new function in a combined way so that the code runs from right to left rather than from inside out.

One of the benefits of function combination and curry is pointfree.

Pointfree mode means that you never have to say your data. It means that the function does not need to mention what data will be manipulated. The function of a class citizen, the curry, and the combination of combinations are very helpful in implementing this pattern.

Non-pointfree because of the data mentioned: Namevar initials = function (name) {  return Name.split ("). Map (Compose (toUpperCase, head)). Join ('. ‘);};/ /pointfreevar initials = Compose (Join ('. '), Map (Compose (toUpperCase, head)), Split (")), Initials (" Hunter Stockton Thompson ");//' H. S. T '

Some thoughts on the curry of JavaScript function

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.