Skip to content

Instantly share code, notes, and snippets.

Created April 9, 2015 07:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/5c4f6ea07ad3017d61be to your computer and use it in GitHub Desktop.
Save anonymous/5c4f6ea07ad3017d61be to your computer and use it in GitHub Desktop.
Syntactic Sugar for Partial Application

Partial Application Syntax Sugar Proposal (a.k.a. Placeholders)

Summary

This proposal defines syntactic sugar for doing partial application in JS.

ES5 defined the bind method for function that allows partial application from the left, but bind doesn't quite cut it for a more functional style of programming. One issue is that it always binds the magic this of the function. Another one is that you can't apply from left, nor at arbitrary positions. Manually writing out the cases is also very verbose, which is something libraries attempt to solve, but given the prevalence of the pattern, this could be solved on the language level as well.

Detailed Design

A "placeholder" is an operator that is placed within function calls to denote partial application. In this proposal I suggest using ? as the placeholder operator because that would signal the intent quite well.

Consider this ES6 example:

const multiply = (a, b) => a * b;
const multiplyBy2 = multiply.bind(null, 2);
const multiplyAllBy2 = (list) => map(list, multiplyBy2);

multiplyAllBy2([1, 2, 3, 4]); // [2, 4, 6, 8]

Using placeholders, this could also be expressed as:

const multiply = (a, b) => a * b;
const multiplyBy2 = multiply(2, ?);
const multiplyAllBy2 = map(?, multiplyBy2);

multiplyAllBy2([1, 2, 3, 4]); // [2, 4, 6, 8]

The placeholder operator also has a "rest" form, similar to spread/rest in ES6. In this case, the rest placeholder operator denotes that zero or more arguments are left unspecified. I'm using ??? as the rest placeholder operator.

Consider this ES6 example:

const printFile = (...args) => {
    fs.readFile(...args, (error, data) => {
        if ( error ) { throw error; }
        console.log(data);
    });
};

printFile("foo.txt", "utf8"); // reads the file as utf8 and prints the result (or crashes on failure).

Using rest placeholders, this could also be expressed as:

const printFile = fs.readFile(???, (error, data) => {
    if ( error ) { throw error; }
    console.log(data);
});

Desugaring

Leading placeholder

Syntax

const bar = foo(?, 1);

Desugaring (ES6)

const bar = ((foo, _1) => {
    return function (_0) {
        return foo.call(this, _0, _1);
    };
}(foo, 1));

Trailing placeholder

Syntax

const bar = foo(2, ?);

Desugaring (ES6)

const bar = ((foo, _0) => {
    return function (_1) {
        return foo.call(this, _0, _1);
    };
}(foo, 2));

Placeholder in the Middle

Syntax

const bar = foo(2, ?, 3);

Desugaring (ES6)

const bar = ((foo, _0, _2) => {
    return function (_1) {
        return foo.call(this, _0, _1, _2);
    };
}(foo, 2, 3));

Rest Placeholder

Syntax

const bar = foo(2, ???, 3);

Desugaring (ES6)

const bar = ((foo, _0, _2) => {
    return function (..._1) {
        return foo.call(this, _0, ..._1, _2);
    };
}(foo, 2, 3));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment