Skip to content

Instantly share code, notes, and snippets.

@benaston
Last active November 23, 2017 11:15
Show Gist options
  • Save benaston/795b644bbbc67098ec2bd388c7060826 to your computer and use it in GitHub Desktop.
Save benaston/795b644bbbc67098ec2bd388c7060826 to your computer and use it in GitHub Desktop.

Motivation

  • Partial application is fundamental to functional-style programming
  • It is the binding of arguments to parameters before a function is invoked
  • This technique is often used by ECMAScript developers who are:
    • seeking to avoid the use of new and/or this
    • deliberately trying to avoid function genericism
    • trying to improve consistency of style
  • Partial application is currently supported by Function.prototype.bind, but the syntax is verbose, and the target of the bound function comes first, diluting the semantic
  • Writing a custom function to provide partial application is straightforward (indeed there are many open source libraries providing this such as _.partial), however developers taking this approach are constrained in their ability to achieve syntactic tenseness lest they surprise other developers
  • A terse, native syntax for partial application that does not affect the target of a function will improve consistency, clarity of intent and legibility

Proposal

Introduce two partial-application operators :>: (partially apply left-to-right) and :<: (partially apply right-to-left). These operators create a bound function such that the arguments to be supplied to the function on the left-hand side of the operator, when it is eventually invoked, are bound to those values supplied on the right-hand side of the operator.

Before

import _ from 'lodash';
const o = { 
  foo: _.partial(foo, arg1),
  bar: bar.bind(null, arg1, arg2)
};

After

const o = { 
  foo:>:arg1,
  bar:>:[arg1, arg2]
};

Before

Promise.resolve()
  .then(() => foo(arg1));

After

Promise.resolve()
  .then(foo:>:arg1);

Examples

const arg1 = 'this is arg1';
function foo(arg1) { console.log(arg1); }

// Current syntax 1
o = { foo: foo.bind(null, arg1) };

// Current syntax 2
let o = { foo: _.partial(foo, arg1) };

// Current syntax 3
let o = { foo: (...args) => foo(arg1, ...args) };

// Proposed syntax
o = { foo:>:arg1 };

o.foo(); // 'this is arg1' printed to console

Use as part of an assignment expression:

const bound = foo:>:context;

As part of a return statement with the spread operator:

function curry(foo, ...args) { return foo:>:[...args]; };

Partial application with multiple arguments. The right-hand side value may be either a single value or an array of arguments:

var bound = foo:>:['a','b'];

If the single value needs to be an array we need to disambiguate:

var bound = foo:>:(['a','b']);

Partial application from the right:

const foo = (a, b) => console.log(a, b);
var bound = foo:<:['this is b'];
bound('this is a'); // 'this is a, this is b' printed to  console

Further considerations

  • I am an unsophisticate with respect to syntax ambiguity avoidance
  • The proposed syntax is merely a first guess and I am confident there will be better ideas
  • I originally chose the syntax :: for the operator, but there is another stage 0 proposal that intends to use that syntax for a different purpose. Also the revised syntax permits identification of the binding direction (from left/from right)
@benaston
Copy link
Author

The proposal that is currently gaining most traction is here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment