1 of 7

PARTIAL APPLICATION

Ron Buckton – Microsoft Corporation

2 of 7

MOTIVATIONS

  • Partially supported via ‘Function#bind()’
    • Can only fix leading arguments.
    • Explicit specification of ‘this’ receiver.
    • All remaining arguments are passed to bound function.
  • Supported via arrow functions
    • With Pipeline, need to write |> (_ => ) for each step.
    • With Pipeline, stack depth becomes ambiguous with multiple steps.

const add = (x, y) => x + y;

// Function#bind

const addOne = add.bind(null, 1);

addOne(2); // 3

// arrow functions

const addTen = x => add(x, 10);

addTen(2); // 12

// arrow functions and pipeline

const newScore = player.score

|> (_ => add(7, _))

|> (_ => clamp(0, 100, _));

3 of 7

PROPOSAL

  • Allow partial application of function calls by fixing arguments and providing placeholders:
    • ? placeholder token
    • ... rest placeholder token
  • Placeholders only permitted in ArgumentList.
  • Result of call is a Function.

// `?` placeholder�f(x, ?) // left apply

f(?, x) // right apply

f(?, x, ?) // middle apply

// `...` rest placeholder�f(x, ...) // left apply

f(..., x) // right apply

f(..., x, ...) // middle apply��// methods�o.f(x, ?)

4 of 7

EXAMPLES

// on its ownconst add = (x, y) => x + y;�const addOne = add(?, 1);�[1, 2, 3].map(addOne); // [2, 3, 4]��// argument limiting�[1].forEach(console.log); // 1 0 [1]�[1].forEach(console.log(?)); // 1�// uncurry 'this'const g = f.call(?, ...);��// add listenerel.addEventListener(this.clicked(?));

// with pipeline, underscore/lodash style�const result = books� |> filter(?, x => x.category === "programming");��// with pipeline, Ramda style�const result = books� |> filter(x => x.category === "programming", ?);

5 of 7

OPEN QUESTIONS

  • Call-by-name vs. call-by-value?
    • Given const g = f(?), what happens when ‘f’ changes?
    • What about a.b()[c++](?)?
  • Eagerly evaluate fixed arguments?
    • Given const g = f(a, ?), what happens when ‘a’ changes?
    • Given const g = create({ a: 1 }, ?), should we get the same object literal value or a fresh one?

6 of 7

STATUS

  • Stage: 0
  • Identified Champions: Ron Buckton, Brian Terlson
  • Strawman available

7 of 7

EXAMPLES

const countOfBooksByAuthor = library

|> descendantsAndSelf(?)

|> filter(?, node => node.category === "programming")

|> groupBy(?, node => node.author)

|> map(?, group => group |> count(?));

const countOfBooksByAuthor = map(

groupBy(

filter(

descendantsAndSelf(library),

node => node.category === "programming"

),

node => node.author

),

group => count(group)

);