From 0d55313589577503772189b05cad3bb46e149204 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=2E=C2=A0S=2E=C2=A0Choi?=
{
values
- |> Object.keys(^)
- |> [...Array.from(new Set(^))]
- |> ^.map(envar => (
+ |> Object.keys(%)
+ |> [...Array.from(new Set(%))]
+ |> %.map(envar => (
+^
is not a final choice
(The precise [**token** for the topic reference is **not final**][token bikeshedding].
-`^` could instead be `%`, or many other tokens.
+`%` could instead be `^`, or many other tokens.
We plan to [**bikeshed** what actual token to use][token bikeshedding]
before advancing to Stage 3.
-However, `^` seems to be the [least syntactically problematic][],
+However, `%` seems to be the [least syntactically problematic][],
and it also resembles the placeholders of **[printf format strings][]**
-and [**Clojure**’s `#(^)` **function literals**][Clojure function literals].)
+and [**Clojure**’s `#(%)` **function literals**][Clojure function literals].)
[least syntactically problematic]: https://github.com/js-choi/proposal-hack-pipes/issues/2
[Clojure function literals]: https://clojure.org/reference/reader#_dispatch
@@ -683,8 +683,8 @@ The pipe operator’s precedence is the **same** as:
It is **tighter** than only the comma operator `,`.\
It is **looser** than **all other** operators.
-For example, `v => v |> ^ == null |> foo(^, 0)`\
-would group into `v => (v |> (^ == null) |> foo(^, 0))`,\
+For example, `v => v |> % == null |> foo(%, 0)`\
+would group into `v => (v |> (% == null) |> foo(%, 0))`,\
which in turn is equivalent to `v => foo(v == null, 0)`.
A pipe body **must** use its topic value **at least once**.
@@ -705,14 +705,14 @@ the assignment operators, and the `yield` operator)
as a **pipe head or body**.
When using `|>` with these operators, we must use **parentheses**
to explicitly indicate what grouping is correct.
-For example, `a |> b ? ^ : c |> ^.d` is invalid syntax;
-it should be corrected to either `a |> (b ? ^ : c) |> ^.d`
-or `a |> (b ? ^ : c |> ^.d)`.
+For example, `a |> b ? % : c |> %.d` is invalid syntax;
+it should be corrected to either `a |> (b ? % : c) |> %.d`
+or `a |> (b ? % : c |> %.d)`.
Lastly, topic bindings **inside dynamically compiled** code
(e.g., with `eval` or `new Function`)
**cannot** be used **outside** of that code.
-For example, `v |> eval('^ + 1')` will throw a syntax error
+For example, `v |> eval('% + 1')` will throw a syntax error
when the `eval` expression is evaluated at runtime.
There are **no other special rules**.
@@ -722,10 +722,10 @@ if we need to interpose a **side effect**
in the middle of a chain of pipe expressions,
without modifying the data being piped through,
then we could use a **comma expression**,
-such as with `value |> (sideEffect(), ^)`.
-As usual, the comma expression will evaluate to its righthand side `^`,
+such as with `value |> (sideEffect(), %)`.
+As usual, the comma expression will evaluate to its righthand side `%`,
essentially passing through the topic value without modifying it.
-This is especially useful for quick debugging: `value |> (console.log(^), ^)`.
+This is especially useful for quick debugging: `value |> (console.log(%), %)`.
## Real-world examples
The only changes to the original examples were dedentation and removal of comments.
@@ -736,7 +736,7 @@ From [jquery/build/tasks/sourceMap.js][]:
var minLoc = Object.keys( grunt.config( "uglify.all.files" ) )[ 0 ];
// With pipes
-var minLoc = grunt.config('uglify.all.files') |> Object.keys(^)[0];
+var minLoc = grunt.config('uglify.all.files') |> Object.keys(%)[0];
```
From [node/deps/npm/lib/unpublish.js][]:
@@ -745,7 +745,7 @@ From [node/deps/npm/lib/unpublish.js][]:
const json = await npmFetch.json(npa(pkgs[0]).escapedName, opts);
// With pipes
-const json = pkgs[0] |> npa(^).escapedName |> await npmFetch.json(^, opts);
+const json = pkgs[0] |> npa(%).escapedName |> await npmFetch.json(%, opts);
```
From [underscore.js][]:
@@ -754,7 +754,7 @@ From [underscore.js][]:
return filter(obj, negate(cb(predicate)), context);
// With pipes
-return cb(predicate) |> _.negate(^) |> _.filter(obj, ^, context);
+return cb(predicate) |> _.negate(%) |> _.filter(obj, %, context);
```
From [ramda.js][].
@@ -764,9 +764,9 @@ return xf['@@transducer/result'](obj[methodName](bind(xf['@@transducer/step'], x
// With pipes
return xf
- |> bind(^['@@transducer/step'], ^)
- |> obj[methodName](^, acc)
- |> xf['@@transducer/result'](^);
+ |> bind(%['@@transducer/step'], %)
+ |> obj[methodName](%, acc)
+ |> xf['@@transducer/result'](%);
```
From [ramda.js][].
@@ -781,11 +781,11 @@ try {
// With pipes: Note the visual parallelism between the two clauses.
try {
return arguments
- |> tryer.apply(this, ^);
+ |> tryer.apply(this, %);
} catch (e) {
return arguments
- |> _concat([e], ^)
- |> catcher.apply(this, ^);
+ |> _concat([e], %)
+ |> catcher.apply(this, %);
}
```
@@ -798,11 +798,11 @@ return this.set('Link', link + Object.keys(links).map(function(rel){
// With pipes
return links
- |> Object.keys(^).map(function (rel) {
+ |> Object.keys(%).map(function (rel) {
return '<' + links[rel] + '>; rel="' + rel + '"';
})
- |> link + ^.join(', ')
- |> this.set('Link', ^);
+ |> link + %.join(', ')
+ |> this.set('Link', %);
```
From [react/scripts/jest/jest-cli.js][].
@@ -822,9 +822,9 @@ console.log(
Object.keys(envars)
.map(envar => `${envar}=${envars[envar]}`)
.join(' ')
- |> `$ ${^}`
- |> chalk.dim(^, 'node', args.join(' '))
- |> console.log(^);
+ |> `$ ${%}`
+ |> chalk.dim(%, 'node', args.join(' '))
+ |> console.log(%);
```
From [ramda.js][].
@@ -834,9 +834,9 @@ return _reduce(xf(typeof fn === 'function' ? _xwrap(fn) : fn), acc, list);
// With pipes
return fn
- |> (typeof ^ === 'function' ? _xwrap(^) : ^)
- |> xf(^)
- |> _reduce(^, acc, list);
+ |> (typeof % === 'function' ? _xwrap(%) : %)
+ |> xf(%)
+ |> _reduce(%, acc, list);
```
From [jquery/src/core/init.js][].
@@ -850,9 +850,9 @@ jQuery.merge( this, jQuery.parseHTML(
// With pipes
context
- |> (^ && ^.nodeType ? ^.ownerDocument || ^ : document)
- |> jQuery.parseHTML(match[1], ^, true)
- |> jQuery.merge(^);
+ |> (% && %.nodeType ? %.ownerDocument || % : document)
+ |> jQuery.parseHTML(match[1], %, true)
+ |> jQuery.merge(%);
```
[ramda.js]: https://github.com/ramda/ramda/blob/v0.27.1/dist/ramda.js
@@ -907,7 +907,7 @@ For example, `f~(?1, ?0)` would have two parameters but would switch them when c
The **second approach** is with a **lazily** evaluated syntax.
This could be handled with an **extension to Hack pipes**,
with a syntax further inspired by
-[Clojure’s `#(%1 %2)` function literals][Clojure function literals].
+[Clojure’s `#(^1 ^2)` function literals][Clojure function literals].
It would do so by **combining** the Hack pipe `|>`
with the **arrow function** `=>`
into a **pipe-function** operator `+>`,
@@ -916,27 +916,27 @@ which would use the same general rules as `|>`.
`+>` would be a **prefix operator** that **creates a new function**,
which in turn **binds its argument(s)** to topic references.
**Non-unary functions** would be created
-by including topic references with **numbers** (`^0`, `^1`, `^2`, etc.) or `...`.
-`^0` (equivalent to plain `^`) would be bound to the **zeroth argument**,
-`^1` would be bound to the next argument, and so on.
-`^...` would be bound to an array of **rest arguments**.
+by including topic references with **numbers** (`%0`, `%1`, `%2`, etc.) or `...`.
+`%0` (equivalent to plain `%`) would be bound to the **zeroth argument**,
+`%1` would be bound to the next argument, and so on.
+`%...` would be bound to an array of **rest arguments**.
And just as with `|>`, `+>` would require its body
to contain at least one topic reference
in order to be syntactically valid.
| Eager PFA | Pipe functions |
| ---------------------------| -------------------------- |
-|`a.map(f~(?, 0))` |`a.map(+> f(^, 0))` |
-|`a.map(f~(?, ?, 0))` |`a.map(+> f(^0, ^1, 0))` |
-|`a.map(x=> x + 1)` |`a.map(+> ^ + 1)` |
-|`a.map(x=> x + x)` |`a.map(+> ^ + ^)` |
-|`a.map(x=> f(x, x))` |`a.map(+> f(^, ^))` |
+|`a.map(f~(?, 0))` |`a.map(+> f(%, 0))` |
+|`a.map(f~(?, ?, 0))` |`a.map(+> f(%0, %1, 0))` |
+|`a.map(x=> x + 1)` |`a.map(+> % + 1)` |
+|`a.map(x=> x + x)` |`a.map(+> % + %)` |
+|`a.map(x=> f(x, x))` |`a.map(+> f(%, %))` |
In contrast to the [eagerly evaluated PFA syntax][PFA syntax],
topic functions would **lazily** evaluate its arguments,
just like how an arrow function would.
-For example, `+> f(g(), ^0, h(), ^1)` would evaluate `f`,
+For example, `+> f(g(), %0, h(), %1)` would evaluate `f`,
and then it would create an arrow function that closes over `g` and `h`.
The created function would **not** evaluate `g()` or `h()`
until the every time the created function is called.
@@ -955,8 +955,8 @@ const fileP = E(
).openFile(fileName);
const fileP = target
-|> E(^).openDirectory(dirName)
-|> E(^).openFile(fileName);
+|> E(%).openDirectory(dirName)
+|> E(%).openFile(fileName);
```
[eventual-send proposal]: https://github.com/tc39/proposal-eventual-send/
@@ -967,22 +967,22 @@ const fileP = target
Many **`if`, `catch`, and `for` statements** could become pithier
if they gained **“pipe syntax”** that bound the topic reference.
-`if () |>` would bind its condition value to `^`,\
-`catch |>` would bind its caught error to `^`,\
-and `for (of) |>` would consecutively bind each of its iterator’s values to `^`.
+`if () |>` would bind its condition value to `%`,\
+`catch |>` would bind its caught error to `%`,\
+and `for (of) |>` would consecutively bind each of its iterator’s values to `%`.
| Status quo | Hack-pipe statement syntax |
| --------------------------- | -------------------------- |
-|`const c = f(); if (c) g(c);`|`if (f()) \|> b(^);` |
-|`catch (e) f(e);` |`catch \|> f(^);` |
-|`for (const v of f()) g(v);` |`for (f()) \|> g(^);` |
+|`const c = f(); if (c) g(c);`|`if (f()) \|> b(%);` |
+|`catch (e) f(e);` |`catch \|> f(%);` |
+|`for (const v of f()) g(v);` |`for (f()) \|> g(%);` |
### Optional Hack pipes
A **short-circuiting** optional-pipe operator `|?>` could also be useful,
much in the way `?.` is useful for optional method calls.
-For example, `value |> (^ == null ? ^ : await foo(^) |> (^ == null ? ^ : ^ + 1))`\
-would be equivalent to `value |?> await foo(^) |?> ^ + 1`.
+For example, `value |> (% == null ? % : await foo(%) |> (% == null ? % : % + 1))`\
+would be equivalent to `value |?> await foo(%) |?> % + 1`.
### Tacit unary function application syntax
**Syntax** for **tacit unary function application** – that is, the F# pipe operator –
@@ -997,8 +997,8 @@ while still not closing off the possibility of an F#-pipe operator.
Secondly, it can be added as **another pipe operator** `|>>` –
similarly to how [Clojure has multiple pipe macros][Clojure pipes]
`->`, `->>`, and `as->`.\
-For example, `value |> ^ + 1 |>> f |> g(^, 0)`\
-would mean `value |> ^ + 1 |> f(^) |> g(^, 0)`.
+For example, `value |> % + 1 |>> f |> g(%, 0)`\
+would mean `value |> % + 1 |> f(%) |> g(%, 0)`.
[Clojure pipes]: https://clojure.org/guides/threading_macros
diff --git a/spec.html b/spec.html
index b011290..ec974dd 100644
--- a/spec.html
+++ b/spec.html
@@ -18,9 +18,9 @@ %
is not a final choiceIntroduction
href=https://github.com/js-choi/proposal-hack-pipes/blob/main/README.md>the proposal's
explainer for the proposal's background, motivation, and usage examples.
This document presumptively uses `^` as the token +
This document presumptively uses `%` as the token for the topic reference. This choice of token is not a final decision; - `^` could instead be `%`.
+ `%` could instead be `^` or some other token.It presumptively uses `^` as the placeholder token for the - topic reference. This choice of token is not a final decision; `^` - could instead be `%`.
+It presumptively uses `%` as the placeholder token for the + topic reference. This choice of token is not a final decision; `%` + could instead be `^` or some other token.
It presumptively uses `^` as the placeholder token for the - topic reference. This choice of token is not a final decision; `^` - could instead be `%`.
+It presumptively uses `%` as the placeholder token for the + topic reference. This choice of token is not a final decision; `%` + could instead be `^` or some other token.
It presumptively uses `^` as the placeholder token for the - topic reference. This choice of token is not a final decision; `^` - could instead be `%`.
+It presumptively uses `%` as the placeholder token for the + topic reference. This choice of token is not a final decision; `%` + could instead be `^` or some other token.
Several early error rules for |ScriptBody| and for |ModuleItemList|, as well as a step in CreateDynamicFunction, - use the Contains operation to check for any unbound topic reference `^`. + use the Contains operation to check for any unbound topic reference `%`. Any inner topic reference within a |PipeBody| is hidden from these rules, preventing them from triggering the rules during program compilation.
@@ -160,15 +160,15 @@It presumptively uses `^` as the placeholder token for the - topic reference. This choice of token is not a final decision; `^` - could instead be `%`.
+It presumptively uses `%` as the placeholder token for the + topic reference. This choice of token is not a final decision; `%` + could instead be `^` or some other token.
It presumptively uses `^` as the placeholder token for the - topic reference. This choice of token is not a final decision; `^` - could instead be `%`.
+It presumptively uses `%` as the placeholder token for the + topic reference. This choice of token is not a final decision; `%` + could instead be `^` or some other token.
@@ -410,13 +410,13 @@It presumptively uses `^` as the placeholder token for the - topic reference. This choice of token is not a final decision; `^` - could instead be `%`.
+It presumptively uses `%` as the placeholder token for the + topic reference. This choice of token is not a final decision; `%` + could instead be `^` or some other token.
The topic binding of a declarative Environment Record - immutably binds the topic reference `^` to one value of any + immutably binds the topic reference `%` to one value of any ECMAScript language type (called the topic value or simply the topic), within that declarative Environment Record, at the time of the Environment Record's instantiation. The topic of a @@ -525,9 +525,9 @@
It presumptively uses `^` as the placeholder token for the - topic reference. This choice of token is not a final decision; `^` - could instead be `%`.
+It presumptively uses `%` as the placeholder token for the + topic reference. This choice of token is not a final decision; `%` + could instead be `^` or some other token.
It presumptively uses `^` as the placeholder token for the - topic reference. This choice of token is not a final decision; `^` - could instead be `%`.
+It presumptively uses `%` as the placeholder token for the + topic reference. This choice of token is not a final decision; `%` + could instead be `^` or some other token.
It presumptively uses `^` as the placeholder token for the - topic reference. This choice of token is not a final decision; `^` - could instead be `%`.
+It presumptively uses `%` as the placeholder token for the + topic reference. This choice of token is not a final decision; `%` + could instead be `^` or some other token.
The topic reference, which is the token `^`, is a +
The topic reference, which is the token `%`, is a nullary operator that evaluates to the current Environment Record's topic value. The topic reference acts as if it were a special variable, implicitly bound to the topic value, yet still lexically scoped. But - `^` is not actually an |IdentifierName| and the topic reference is + `%` is not actually an |IdentifierName| and the topic reference is not a variable, and it cannot be bound by typical assignment. Instead, the topic reference is immutably bound to a value during the instantiation of any topic-binding environment by a |PipeBody|.
@@ -631,7 +631,7 @@This section is a wholly new sub-clause.
-It presumptively uses `^` as the placeholder token for the - topic reference. This choice of token is not a final decision; `^` - could instead be `%`.
+It presumptively uses `%` as the placeholder token for the + topic reference. This choice of token is not a final decision; `%` + could instead be `^` or some other token.
It presumptively uses `^` as the placeholder token for the - topic reference. This choice of token is not a final decision; `^` - could instead be `%`.
+It presumptively uses `%` as the placeholder token for the + topic reference. This choice of token is not a final decision; `%` + could instead be `^` or some other token.
It presumptively uses `^` as the placeholder token for the - topic reference. This choice of token is not a final decision; `^` - could instead be `%`.
+It presumptively uses `%` as the placeholder token for the + topic reference. This choice of token is not a final decision; `%` + could instead be `^` or some other token.
It presumptively uses `^` as the placeholder token for the - topic reference. This choice of token is not a final decision; `^` - could instead be `%`.
+It presumptively uses `%` as the placeholder token for the + topic reference. This choice of token is not a final decision; `%` + could instead be `^` or some other token.