Closed caesarsol closed 5 years ago
What about ...?
, implying you're spreading placeholders?
@Haroenv seems to close to spread/rest op syntax (IMO); I.e., I take it back (lol) I think the solutions for this require more study as there are still other "possible features that could/should-(probably) be considered as part of partial application solution (namely currying in general)....rest
The ...
token in partial application would be a direct parallel to both function "rest" parameters and call "spread" arguments, as it serves both purposes:
function f(...args) { console.log(JSON.stringify(args)); }
const g = f(1, ...);
g(2, 3); // [1, 2, 3]
Since it is effectively transposed as:
const g = (() => {
const fn = f;
const p0 = 1;
return (...an) => fn(p0, ...an); // <- transposition of `...`
}();
I have also considered allowing ?...
to mean "spread ?
into the call here":
function f(...args) { console.log(JSON.stringify(args)); }
const g = f(1, ?...);
g([2, 3]); // [1, 2, 3];
As well as allowing ...?
to mean "all the rest of the args go here":
function f(...args) { console.log(JSON.stringify(args)); }
const g = f(1, ...?);
g(2, 3); // [1, [2, 3]];
In which case ...?...
would be synonymous with ...
(and therefore unnecessary).
I think that ?...
and ...?
should be swapped: ...SOMETHING
in function calls already is an array spread.
@nicolo-ribaudo It's also used for rest in function parameters, and ?
is both the argument for the call and the parameter for the resulting function. Its ambiguous either way:
function f(a, b, ...rest) {}
f(a, b, ...spread) {}
const [a, b, ...rest] = ar;
ar = [a, b, ...spread];
const { a, b, ...rest } = obj;
obj = { a, b, ...spread };
Therefore its highly ambiguous in partial application:
const g1 = f(a, b, ...); // both rest and spread (not ambiguous)
const g2 = f(a, b, ...?); // is this a `...rest` or a `...spread`?
If we were to support disambiguating the two, having ...
on one side or the other of ?
indicates direction and cardinality:
?
indicates a "one" binding.
(i.e. "take the one argument and put it in this one place")...
indicates a "many" binding.
(i.e. "take the many rest arguments and spread its many elements in this place")...?
indicates a "many-to-one" binding.
(i.e. "take the many rest arguments (...
) and put it in this one place (?
)")?...
indicates a "one-to-many" binding.
(i.e. "take this one argument (?
) and spread its many elements this place (...
)")Otherwise we'd need a different syntax to disambiguate direction (i.e. ...<?
, ...>?
).
In general I believe its simpler to just have ?
(and possibly ...
) and avoid the complexity/ambiguity of the one-to-many/many-to-one representations.
Closing for now as the current proposal draft as removed support for the ...
operator. We may reopen this issue for further discussion at a later date, should we decide to reintroduce this support in this or a follow-on proposal.
In case this gets re-opened, how about just using parens:
macro y = |
transpiled y = |
y(a,b) calls f with |
---|---|---|
f(?) |
(x) => f(x) |
a |
f(...?) |
(...x) => f(...x) |
a, b |
f([...?]) |
(...x) => f([...x]) |
[a, b] |
f({...?}) |
(...x) => f({...x}) |
{0: a, 1: b} |
f([...(?)]) |
(x) => f([...x]) |
[...a] |
f({...(?)}) |
(x) => f({...x}) |
{...a} |
Parens are already commonly used to clear up syntax (e.g. () => {}
vs () => ({})
), and it feels very easy to remember.
It could also play well with types: foo(...(?: string))
vs foo(...?: string[])
although that example looks much better with _
.
I think ?...
is better for rest and ...?
for spread. Considering ?0
, ?1
... for specific arg, ?...
for the rest args are reasonable. On the other hand, ...?
for spread is intuitive and far-sighted, we can extend it to ...?0
, ...?1
... in fact, we can assume ...?
as shortcut for ...?0
and ...
for ...?...
I think having both ...?
and ?...
are always confusing, we'd better only use ...
.
f(❓) // x => f(x)
f(1, ..., 2) // (...x) => f(1, ...x, 2)
f(1, [...], 2) // (...x) => f(1, x, 2)
f(❓1, ...❓2, ...) // (x, y, ...z) => f(x, ...y, ...z)
(I use ❓
here for any character we finally decide, personally I prefer %
which follow DOS batch script 😆, so use %
in follow code example)
Ambiguity only occur if use both %
and ...
, so we'd better ban it!
f(...%,...) // syntax error!
f(...%1,...) // much clear what we want
// actually having multiple % is also confusing, we'd better also ban it
f(%, ..., %) // what this mean?
f(%1, ..., %1) // (x, ...y) => f(x, ...y, x) or
f(%1, ..., %2) // (x, y, ...z) => f(x, ...z, y) or
// (x, ...y) => f(x, y.slice(0, -1), y[y.length - 1]) ???
Current proposal use f(%1, ..., %2)
semantic, but if consider ...
, the order is not preserved any more which may cause confusion.
PS. the last semantic could be supported in the future by introducing %^n
syntax: f(%1, ..., %^1)
(^n
is coming from the discussion of slice notation proposal)
PPS. I use %1
instead of %0
because:
I think the
...
operator could lead to confusion, being it already used for array destructuring and function variadic arguments.My proposal is to use something more like
?...
, that would be consistent with the other proposal #5 on the positional placeholders.