Too many operators can become quite confusing, having worked with many functional languages I find the number of operators more of a hinder than help. I’m very pro functional operators when they help me read the code explicitly rather than implicitly, for example with the `|>` pipeline operator, this helps you to read the code in the order of execution. With the current `|>` operator proposal you could write something similar with:
`const sum = numbers |> (numbers) => reduce(numbers, (a, b) => a + b);` Passing numbers to an anonymous closure so you can have multiple arguments works quite elegantly. David > On 17 Jul 2017, at 00:11, [email protected] wrote: > > Send es-discuss mailing list submissions to > [email protected] <mailto:[email protected]> > > To subscribe or unsubscribe via the World Wide Web, visit > https://mail.mozilla.org/listinfo/es-discuss > <https://mail.mozilla.org/listinfo/es-discuss> > or, via email, send a message with subject or body 'help' to > [email protected] <mailto:[email protected]> > > You can reach the person managing the list at > [email protected] <mailto:[email protected]> > > When replying, please edit your Subject line so it is more specific > than "Re: Contents of es-discuss digest..." > Today's Topics: > > 1. RE: Re: Functional Operators (doodad-js Admin) > 2. Re: Array.prototype.tap (Eli White) > > From: "doodad-js Admin" <[email protected] <mailto:[email protected]>> > Subject: RE: Re: Functional Operators > Date: 16 July 2017 at 23:44:53 BST > To: "'Ron Buckton'" <[email protected] > <mailto:[email protected]>>, "'Darien Valentine'" > <[email protected] <mailto:[email protected]>>, > <[email protected] <mailto:[email protected]>> > > > One question I have: why all these fuzzy (sorry, functional) operators? That > could become very hard to know what the code exactly does, and difficult to > debug... Are you becoming too “lazy” to type on the keyboard? > > > From: Ron Buckton [mailto:[email protected] > <mailto:[email protected]>] > Sent: Sunday, July 16, 2017 3:54 PM > To: Darien Valentine <[email protected] <mailto:[email protected]>>; > [email protected] <mailto:[email protected]> > Subject: RE: Re: Functional Operators > > (apologies for top posting as I’m replying from my phone) > > Functional operators are not very interesting on their own, but are much more > interesting in terms of pipelines and partial application. However, they may > be a stretch in either scenario, so I’m not expecting them to be part of any > official proposal for pipeline/partial application at this time. > > By ergonomic, I meant that ‘{+}’ is far fewer characters than ‘Math.add’. > Also, not every ‘+’ is arithmetic (i.e. string concatenation). > > I can imagine a world where I can do: > > ```js > const sum = numbers |> reduce(?, {+}); > const joined = strings |> reduce(?, {+}); > ``` > > As a shorthand for: > > ```js > const sum = numbers |> reduce(?, (a, b) => a + b); > const joined = strings |> reduce(?, (a, b) => a + b); > ``` > > (I’m using `|>` here for pipeline and `?` as a positional argument for > partial application here) > > Ron > > From: Darien Valentine <mailto:[email protected]> > Sent: Sunday, July 16, 2017 1:18 AM > To: [email protected] <mailto:[email protected]> > Subject: Re: Re: Functional Operators > > If I understand right, Ron, it means a new RHS for PrimaryExpression and > would behave like a reference, except that it is (presumably) not a valid > assignment target? Can you explain more about the ergonomics — maybe it’s > just from lack of familiarity, but to me this seems pretty grawlixy, like > something you’d see in Perl. > > In other words, I’m unsure how `arr.reduce({+})` is more ergonomic than > `arr.reduce(Math.add)`\*. Assuming it is and I’m just failing to see it, is > the benefit significant enough to merit new syntax? > > (On further consideration, maybe `Reflect.add`, since `+` is not specific to > numeric values...) > > On Sun, Jul 16, 2017 at 2:19 AM, Ron Buckton <[email protected] > <mailto:[email protected]>> wrote: > I have been looking into functional operators while working on a proposal for > pipeline and partial application. I’ve found that a sigil like `{+}` is just > as ergonomic as `(+)`, but has fewer lookahead issues with respect to regular > expression parsing. While `(/)` is ambiguous as to whether it would be a > division function or the start of a parenthesized regular expression literal, > `{/` is far less ambiguous in most expression positions. The only ambiguity > is at the statement level where `{/` could be interpreted as the start of a > block with a regular expression literal. However, it is fairly unlikely this > expression would be used in this position, and this can be mitigated using > parentheses just as we do for object assignment patterns in destructuring > assignments. > > The other ambiguous case is how to differentiate between overloaded binary > and unary operators. For that, I’ve considered following the approach taken > by F# and prefixing overloaded unary operators with tilde. As such `{+}` > would always be a binary plus function, while `{~+}` would be the unary plus > function. In the same vein, `{-}` would be binary minus, while `{~-}` would > be the unary minus function. For non-overloaded unary operators the prefix is > unnecessary, so `{~}` and `{!}` would not be prefixed. > > While built-ins could serve this case, they are far less ergonomic than a > shorthand sigil for an operator. On the other hand, we could have both, with > the operator sigils acting as shorthand for the long-form built-in methods. > Either way, I would expect `{+} === {+}` as there is no sense in allocating a > fresh function object each time it is encountered. Ideally, these would be > frozen functions that are created once per realm and have the same semantics > as an arrow function (i.e. [[Call]] but no [[Construct]], etc.). > > Ron > <> > From: es-discuss [mailto:[email protected] > <mailto:[email protected]>] On Behalf Of Darien Valentine > Sent: Monday, July 10, 2017 3:08 PM > To: [email protected] <mailto:[email protected]> > Subject: Re: Re: Functional Operators > > Minor point regarding the syntax given here: introducing `(/)` would likely > be problematic because it breaks the constraint that there are no positions > in the grammar where both a division operator and a regular expression > literal could be valid continuations. > > (Perhaps new built-ins like `Math.add` etc might represent a more consistent > approach to the issue of operators not being function references?) > > > > > From: Eli White <[email protected] <mailto:[email protected]>> > Subject: Re: Array.prototype.tap > Date: 17 July 2017 at 00:11:24 BST > To: Vinnymac <[email protected] <mailto:[email protected]>> > Cc: es-discuss <[email protected] <mailto:[email protected]>> > > > I do not believe `.forEach` with a return value would satisfy this usage > because with `.tap`, the callback is called only once, with the first > argument being the *entire* array. > > On Sun, Jul 16, 2017 at 3:37 PM, Vinnymac <[email protected] > <mailto:[email protected]>> wrote: > I have been reading over the `.forEach` with a return value discussion. I > imagine if that was added it would work with chaining and do everything that > `.tap` would be capable of. Unless I have missed something? > > On Jul 16, 2017 3:55 PM, "Eli White" <[email protected] > <mailto:[email protected]>> wrote: > This is definitely something that can be polyfilled (with different levels of > naivety) but requires modifying built-ins which is a no-no. > > Here is an example that is more valuable in production than just debugging. > > Many other languages that support `.tap` enable a value to be returned. If it > is, that value is passed down the rest of the chain instead of the initial > value (but the return value is optional). This is also functionally similar > to `.tee` in many languages (and bash). > https://en.wikipedia.org/wiki/Tee_(command) > <https://en.wikipedia.org/wiki/Tee_(command)> > > One of the other common use cases for `.tap` is to be able to chain methods > that act on the entire array. For example, if `.reverse` wasn't part of > `Array.prototype` and instead you had a user function `myReverse(arr) => > arr'`, then if you wanted to convert `[1,2,3]` into `["6","4","2"]`, then > you'd have to do the following. It is a bit of a contrived example since I'm > avoiding just calling `myReverse` before or after the chain. Imagine a more > complex example and longer chain. > > ``` > const value = [1, 2, 3].map(String); > myReverse(value).map(num => num * 2); > ``` > > With `.tap`, it can be part of the chain: > > ``` > const value = [1, 2, 3] > .map(String) > .tap(myReverse) > .map(num => num * 2); > ``` > > Obviously this could be done with reduce, but it would require `myReverse` to > have a different signature. > > Just trying to provide some reasoning why `.tap` is for more than just > debugging. :) > > > On Sun, Jul 16, 2017 at 12:00 PM, Bob Myers <[email protected] > <mailto:[email protected]>> wrote: > ```js > Object.defineProperty(Array.prototype, 'tap', { > value: function(fn) { fn(this); return this;} > }); > ``` > > On Mon, Jul 17, 2017 at 12:15 AM, Logan Smyth <[email protected] > <mailto:[email protected]>> wrote: > You could always hack it and use the third argument :D > > ``` > var tap = f => (v, i, arr) => { > if (i === arr.length - 1) f(arr); > > return v; > }; > ``` > > Fine for debugging at least, but not necessarily your overall goal. > > On Sun, Jul 16, 2017 at 11:20 AM, Eli White <[email protected] > <mailto:[email protected]>> wrote: > That leads to a different result. Map is called once for every item in the > array. > > ``` > const tap = f => x => { > f(x); > return x; > } > > [1, 2, 3] > .map(num => num * 2) > .map(tap(console.log.bind(console))) > .reduce((a, b) => a + b); > ``` > > Results in: > > ``` > 2 > 4 > 6 > ``` > > Whereas > > ``` > [1, 2, 3] > .map(num => num * 2) > .tap(console.log.bind(console)); > .reduce((a, b) => a + b); > ``` > > would result in > > ``` > [2, 4, 6] > ``` > > This is what makes it hard about being a userland function. Tap enables the > developer to act on the *entire* array, not individual items. > > On Sun, Jul 16, 2017 at 11:10 AM, Elie Rotenberg <[email protected] > <mailto:[email protected]>> wrote: > Sorry I meant: > > const tap = f => x => { > f(x); > return x; > } > > > > Elie ROTENBERG > Directeur général adjoint > [email protected] <mailto:[email protected]> > 336 89 29 98 19 > twitter elierotenberg facebook elie.rotenberg skype elie.rotenberg github > elierotenberg > > 2, rue Paul Vaillant Couturier - CS 60102 - 92532 Levallois-Perret Cedex - T: > 33 811 69 41 42 > > > On Sun, Jul 16, 2017 at 8:09 PM, Elie Rotenberg <[email protected] > <mailto:[email protected]>> wrote: > I think the most common use of this pattern would be debugging, and in this > context you don't really care to use a little helper and Array.prototype.map, > eg: > > const tap = f => ...args => { > f(...args); > return x; > }; > > [1, 2, 3] > .map(num => num * 2) > .map(tap(console.log.bind(console))); > .reduce((a, b) => a + b); > > > On Sun, Jul 16, 2017 at 8:00 PM, Eli White <[email protected] > <mailto:[email protected]>> wrote: > I'd like to propose a `.tap` method on the Array prototype. I was able to > find some previous discussion here but it was off the main topic and seemed > to die out: > https://mail.mozilla.org/pipermail/es-discuss/2015-October/044454.html > <https://mail.mozilla.org/pipermail/es-discuss/2015-October/044454.html> > > A tap method enables the user to inspect an array in the chain. > > For example, inspection: > > If you have a chain like this: > > ``` > [1, 2, 3] > .map(num => num * 2) > .reduce((a, b) => a + b); > ``` > > When you want to see what the value of the array is between the map and > reduce, you would typically do this: > > ``` > const value = [1, 2, 3] > .map(num => num * 2); > > console.log(value); > > value.reduce((a, b) => a + b); > ``` > > With `.tap`, you'd be able to do this: > > ``` > [1, 2, 3] > .map(num => num * 2) > .tap(console.log.bind(console)); > .reduce((a, b) => a + b); > ``` > > `.tap` would be called once, passed the entire array as the first argument to > the callback, and would return the array after the callback was finished. > > This isn't something that can cleanly be done with a user-land function since > it would have to wrap the chain, or replace all of the chained functions like > underscore does. > > An example of wrapping the chain: > > ``` > myTap( > ( > [1, 2, 3] > .map(num => num * 2) > ), > console.log.bind(console); > ) > .reduce((a, b) => a + b); > ``` > > _______________________________________________ > es-discuss mailing list > [email protected] <mailto:[email protected]> > https://mail.mozilla.org/listinfo/es-discuss > <https://mail.mozilla.org/listinfo/es-discuss> > > > > > > _______________________________________________ > es-discuss mailing list > [email protected] <mailto:[email protected]> > https://mail.mozilla.org/listinfo/es-discuss > <https://mail.mozilla.org/listinfo/es-discuss> > > > > _______________________________________________ > es-discuss mailing list > [email protected] <mailto:[email protected]> > https://mail.mozilla.org/listinfo/es-discuss > <https://mail.mozilla.org/listinfo/es-discuss> > > > > > _______________________________________________ > es-discuss mailing list > [email protected] <mailto:[email protected]> > https://mail.mozilla.org/listinfo/es-discuss > <https://mail.mozilla.org/listinfo/es-discuss> > > > > > _______________________________________________ > es-discuss mailing list > [email protected] <mailto:[email protected]> > https://mail.mozilla.org/listinfo/es-discuss > <https://mail.mozilla.org/listinfo/es-discuss>
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

