es-discuss Digest, Vol 125, Issue 51

David White david.rhys.white at icloud.com
Mon Jul 17 01:34:10 UTC 2017


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, es-discuss-request at mozilla.org wrote:
> 
> Send es-discuss mailing list submissions to
> 	es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> 
> 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
> 	es-discuss-request at mozilla.org <mailto:es-discuss-request at mozilla.org>
> 
> You can reach the person managing the list at
> 	es-discuss-owner at mozilla.org <mailto:es-discuss-owner at mozilla.org>
> 
> 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" <doodadjs at gmail.com <mailto:doodadjs at gmail.com>>
> Subject: RE: Re: Functional Operators
> Date: 16 July 2017 at 23:44:53 BST
> To: "'Ron Buckton'" <Ron.Buckton at microsoft.com <mailto:Ron.Buckton at microsoft.com>>, "'Darien Valentine'" <valentinium at gmail.com <mailto:valentinium at gmail.com>>, <es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>>
> 
> 
> 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:Ron.Buckton at microsoft.com <mailto:Ron.Buckton at microsoft.com>] 
> Sent: Sunday, July 16, 2017 3:54 PM
> To: Darien Valentine <valentinium at gmail.com <mailto:valentinium at gmail.com>>; es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> 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:valentinium at gmail.com>
> Sent: Sunday, July 16, 2017 1:18 AM
> To: es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> 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 <Ron.Buckton at microsoft.com <mailto:Ron.Buckton at microsoft.com>> 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:es-discuss-bounces at mozilla.org <mailto:es-discuss-bounces at mozilla.org>] On Behalf Of Darien Valentine
> Sent: Monday, July 10, 2017 3:08 PM
> To: es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> 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 <ecma at eli-white.com <mailto:ecma at eli-white.com>>
> Subject: Re: Array.prototype.tap
> Date: 17 July 2017 at 00:11:24 BST
> To: Vinnymac <vinnymac at gmail.com <mailto:vinnymac at gmail.com>>
> Cc: es-discuss <es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>>
> 
> 
> 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 <vinnymac at gmail.com <mailto:vinnymac at gmail.com>> 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" <ecma at eli-white.com <mailto:ecma at eli-white.com>> 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 <rtm at gol.com <mailto:rtm at gol.com>> 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 <loganfsmyth at gmail.com <mailto:loganfsmyth at gmail.com>> 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 <ecma at eli-white.com <mailto:ecma at eli-white.com>> 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 <elie at rotenberg.io <mailto:elie at rotenberg.io>> wrote:
> Sorry I meant:
> 
> const tap = f => x => {
>   f(x);
>   return x;
> }
> 
> 
> 
> Elie ROTENBERG
> Directeur général adjoint
> elie.rotenberg at webedia-group.com <mailto:elie.rotenberg at webedia-group.com>
> 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 <elie at rotenberg.io <mailto:elie at rotenberg.io>> 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 <ecma at eli-white.com <mailto:ecma at eli-white.com>> 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
> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss>
> 
> 
> 
> 
> 
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss>
> 
> 
> 
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss>
> 
> 
> 
> 
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss>
> 
> 
> 
> 
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> https://mail.mozilla.org/listinfo/es-discuss <https://mail.mozilla.org/listinfo/es-discuss>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170717/f43b562c/attachment-0001.html>


More information about the es-discuss mailing list