This is the 4th day of my participation in the August More Text Challenge.

preface

Both Collerization and partial functions are important concepts in functional programming, and today we are going to do a little bit different inverse Collerization.

But since it is anti-Cremation, let’s first understand its sister Cremation and partial functions.

Currie and partial functions

1.1 Mr Currie

Wikipedia says:

Currying, English: Currying, is a technique that converts a function that takes multiple arguments into a function that takes a single argument (the first argument of the original function), and returns a new function that takes the remaining arguments and returns a result.

The technique was named after logician Haskell Curry by Christopher Strachey, although it was invented by Moses Schnfinkel and Gottlob Frege.

Let’s look at an example, which is intuitive:

function sum(a, b, c) {
  return a + b + c;
}

function currySum(a){
    return function (b){
        return function (c){
            return a + b + c;
        }
    }
}
sum(1.2.3) / / 6
currySum(1) (2) (3) / / 6

Copy the code

To put it simply, there are two points:

  1. More paragraphs to participate

  2. A function that satisfies the condition that it executes the function and returns the result

1.1.1 the difficulty

The difficulty of the general Caulization function is how to know the length of function parameters. The commonly used means are as follows:

  1. Function. The prototype. The length attribute for parameter length

    The downside is that rest parameters are not counted in length.

    The following code, which gets a length of 2, is the best fact.

    function log(msg1, msg2, ... other){
        console.log(msg1, msg2, ... other); }console.log(log.length); / / 2
    Copy the code
  2. Display the length of the incoming argument when currified

  3. Of course, you can combine the two, a function default value is ok

    function curry(fn, length = fn.length){
        / /...
    }
    Copy the code

1.1.2 placeholder


The concept of having a placeholder after curryification means that I will pass this parameter in later.

Take a look at the official Lodash example.

var abc = function(a, b, c) {
  return [a, b, c];
};
 
var curried = _.curry(abc);
// Curried with placeholders.
curried(1) (_,3) (2);
// => [1, 2, 3]
Copy the code

As for the implementation, the advanced version of Lodash.curry, the civilian version of JavaScript, has a special function called Currization.

1.2 partial function

Similar to Currization, simply understand that parameters are passed twice

  1. Fixed some parameters for the first time
  2. The remaining parameters are passed in a second time

Take a look at the underscore official example, which also has placeholders, but does not affect understanding.

var subtract = function(a, b) { return b - a; };
sub5 = _.partial(subtract, 5);
sub5(20); = >15

// Using a placeholder
subFrom20 = _.partial(subtract, _, 20);
subFrom20(5); = >15
Copy the code

As for implementation, advanced versions lodash.partial and underscore. Partial are JavaScript thematic partial functions

Up to this point, partial functions are similar in functionality to bind.

But that’s not the point of today, the point of today is anti-Corrification.

The curry

2.1 concept

Anti-cremation is the doctrine of taking something from someone else and using it.

Look at an example: we are commonly used to determine the data type of the Object. The prototype. ToString

function unCurry(fn) {
    return function (context) {
        return fn.apply(context, Array.prototype.slice.call(arguments.1)); }}// Do not use anti-Currization
Object.prototype.toString.call({});  // [object Object]

// Reverse Corrification
const toString = unCurry(Object.prototype.toString);
toString({});        // [object Object]
toString(() = >{});// [object Function]
toString(1);         // [object Number]
Copy the code

2.2 implementation

2.2.1 Basic version: Easy to understand

function unCurry(fn) {
    return function (context) {
        return fn.apply(context, Array.prototype.slice.call(arguments.1)); }}Copy the code

2.2.2 Prototype version: Intrusion + convenience

Function.prototype.unCurry = function(){
    var self = this;
    return function(){
        return Function.prototype.call.apply(self, arguments); }}Copy the code

This version invades the prototype, and I don’t like it. There is some convenience. There are two difficulties in understanding

  1. Self = this self is equal to the function itself, so this is the staging function

  2. Function.prototype.call.apply(self, arguments)

It’s a hassle to talk about, but look at the conversion below.

Function.prototype.call.apply(self, arguments) = = >Function.prototype.call.bind(self)(arguments)
==>
self.call(arguments)
==>
self.call(arguments[0].arguments[1-n]) // arguments[0] is the context for self function
Copy the code

It changes slightly when you use it

2.2.3 Prototype version 2

I’m not going to read into that, but you can make your own waves

Function.prototype.unCurry = function () {
    return this.call.bind(this);
};

Copy the code

With ES6, does the following code also work?

Function.prototype.unCurry = function () {
    return (. args) = > this.call(... args) };Copy the code

There are a variety of interesting ways to write this, for more details, see # Currified && Anti-Currified

2.3 Application Scenarios

Anti-corrification is a way of thinking, and its implementation can certainly be replaced by other schemes, but one more way of thinking, one more means.

2.3.1 Determine the data type

This was demonstrated in the demo above.

2.3.2 Array push (example in advanced programming)

const push = unCurry(Array.prototype.push);
const arr = [1.2.3];
push(arr, 4.5.6);
console.log(arr);

Copy the code

2.3.3 Copying an Array

const clone = unCurry(Array.prototype.slice);

var a = [1.2.3];

var b = clone(a);

console.log("a==b", a === b);  // a==b false
console.log(a, b);  // [1, 2, 3] [1, 2, 3]

Copy the code

2.3.4 Sending Events

    const dispatch = unCurry(EventTarget.prototype.dispatchEvent);

    window.addEventListener("event-x".(ev) = > {
        console.log("event-x", ev.detail);  // event-x ok
    })

    dispatch(window.new CustomEvent("event-x", { detail: "ok" }));

Copy the code

Detailed solution of JS function coriolization

Collerization and anti-Collerization

JavaScript thematic partial functions