-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Syntactic marker for partial application #48
Comments
Why about optional partial application? In other words, i assume |
The chaining example makes my head hurt. Can you explain what it is without using |
@jridgewell I believe it indicates that |
There are two issues that confuse me:
|
@jridgewell i think it's more like, |
The point of showing how method chaining works isn't to show its a good idea, but that it is consistent with the language. I'm not yet sure whether optional partial application should be permitted. It wouldn't be the only calling convention that doesn't support optional chaining. If it was supported, it might look like this:
In either case, the result would return |
This change would make me so happy, and remove all of my blocking concerns with PFA:
I'm a big supporter of all this. |
What should |
Syntax error - the ~ is part of the call operator, so the operator is actually
The import() function, yeah. It's just a normal function that returns a promise; it can be PFA'd like anything else. (I'm pretty sure import() doesn't get figured into the module dependency tree, right?) The |
|
I explicitly don't allow |
Yeah, my bad for thinking import() was a normal function. Any of the "magic" functions (that can't just be squirreled away in a closure for later) shouldn't be PFA-able. |
I made a TypeScript PR implementing some parts of this variant. I'm thinking of dropping support for old-form |
History
One of the original goals for partial application was to dovetail with F#-style pipelines using minimal syntax. For example:
I have long favored the terseness of the above approach, but partial application has long been blocked on concerns about "The Garden Path", that there was no indication that
f(a, b, c, /* ... */ ?)
was a partial call until you encountered the placeholder.Recently, TC39 advanced Hack-style pipelines to Stage 2. This is, in a way, a blessing for partial application. Having partial application divorced from the pipeline syntax means there's less impetus behind pushing for an extremely terse syntax. As a result, I am far more comfortable with requiring a syntactic marker to indicate a partially-applied invocation.
Proposal
Thus, I propose the following syntax for partial application:
fn~(a, ?, b)
While we can bikeshed the specific marker, there are a number of reasons why I'm proposing
f~(?)
over alternatives like+> f(?)
:f~()
indicates a separate calling convention fromf()
, not unlikef?.()
(but without the need for the.
disambiguator).bind()
operation:a
is preserved asthis
fora.b~()
)?
) are mapped directly to arguments in the new functionf~()
new
with a clear meaning: Inconst f = new C~(arg, ?);
,f
can be called since thenew
is part of the partial application.+>
variants (as proposed for "smart-mix" pipelines and as an addendum to Hack-style pipelines) are lazily evaluated, essentially acting like an arrow function.By placing the marker coterminous with Arguments, we can clearly indicate that what is affected is the argument list, rather than an arbitrary expression. For example, in an earlier investigation into a syntactic marker we considered using a prefix
^
before the expression:^f(?)
. Given the intended eager semantics of partial application, such a prefix can become confusing. Given^a.b().c(?)
, should this have been a syntax error? If not, how would you have differentiated between which invocation was partial? Would we have required parenthesis around the non-partial left-hand-side (i.e.,^(a.b()).c(?)
)?Instead, we've chosen to include the marker as part of Arguments to make the locality of the partial application more explicit. The expression
a.b().c~(?)
does not require parenthesis to disambiguate, and as a result can be easily chained:a.b~(?, ?).apply~(null, ?)
.Examples
Here are some examples of this proposed syntax change to provide context:
argument binding
chaining
Uncurrying
this
The
~(
syntactic marker does allow you to uncurry thethis
argument of a function:Caveat - No placeholder for Callee
The
~(
syntactic marker does not address the possibility of having the callee itself be a placeholder. That is a corner case that is outside the scope of the proposal and can be easily solved in userland either using arrow functions or simple definitions likeinvoke
, below:Re-introduce
...
placeholderFinally, as part of introducing
~(
, we intend to also re-introduce...
as the "remaining arguments" placeholder (see #18) so that we can cover all of the following cases:Given
const f = (...args) => console.log(...args);
:f~()
- Partially applyf
with fixed arguments and no placeholders:f~(?)
- Partially applyf
with fixed arguments and one or more placeholders:f~(...)
- Partially applyf
with fixed arguments and a remaining arguments placeholder:f~(?, ...)
orf~(..., ?)
- Partially applyf
with fixed arguments, one or more placeholders, and a remaining arguments placeholder:The
...
operator always means "spread any remaining unbound arguments into this argument position".Relation to
.bind
and the "bind" operator (::
)Reintroducing
...
would mean thato.m~(...)
would be a syntactic shorthand foro.m.bind(o)
:It also means that
o.m~(...)
could serve as a replacement for the proposed prefix-bind operator (i.e.,::o.m
), though that does not necessarily mean that prefix-bind should not be considered.Neither partial application nor its use of
...
are able or intended to replace the proposed infix-bind operator (i.e.,o::m
).Related Issues
See the following related issues for additional historical context:
new
with the partial application #11The text was updated successfully, but these errors were encountered: