From toth@dene@ @end|ng |rom kogentum@hu  Sun Dec  6 15:43:26 2020
From: toth@dene@ @end|ng |rom kogentum@hu (=?UTF-8?B?RMOpbmVzIFTDs3Ro?=)
Date: Sun, 6 Dec 2020 15:43:26 +0100
Subject: [Rd] [External] Re: New pipe operator
In-Reply-To: <alpine.DEB.2.21.2012051203250.3003@luke-Latitude-7480>
References: <e55c2093-0bb5-5f9b-5521-0ca8bdf35953@gmail.com>
 <CALyqOb8c1hHOSaMV+fqXTwpeOsP--KJ_t-oeqMYYafVXeNpqZg@mail.gmail.com>
 <7586e034-e287-0970-6480-f82d747b5445@gmail.com>
 <CADfFDC7bT58_+52uvmpHuMMQRNbbmqV3_7t_fc4sgJ_Esw=xag@mail.gmail.com>
 <CAJmOi+PO_8XDC23=rT=pQ76ENL=gx2V-41ax2fHSVs87xURcEA@mail.gmail.com>
 <alpine.DEB.2.21.2012051203250.3003@luke-Latitude-7480>
Message-ID: <b1540fd5-339b-1a4c-440e-b683c86b4315@kogentum.hu>

Dear Luke,

In the meantime I checked the R-syntax branch and the docs; they are 
very helpful. I would also like to thank you for putting effort into 
this feature. Keeping it at the syntax level is also a very smart 
decision. However, the current API might not exploit the full power of 
the basic idea.

1) Requiring either an anonymous function or a function call, but not 
allowing for symbols which point to functions is inconsistent and will 
be misleading for non-experts.

foo <- function(x) x
identical(foo, function(x) x)

mtcars |> foo               #bang!
mtcars |> function(x) x     #fine?

You stated in :
"
Another variation supported by the implementation is that a symbol on
the RHS is interpreted as the name of a function to call with the LHS
as argument:

```r
 > quote(x |> f)
f(x)
```
"

So clearly this is not an implementation issue but a design decision.

As a remedy, two different pipe operators could be introduced:

LHS |> RHS    -> RHS is treated as a function call
LHS |>> RHS   -> RHS is treated as a function

If |>> is used, it would not matter which notation is used for the RHS 
expression; the parser would assume it evaluates to a function.

2) Simplified lambda expression:
IMHO in the vast majority of use cases, this is used for single-argument 
functions, so parenthesis would not be required. Hence, both forms would 
be valid and equivalent:

\x x + 1
\(x) x + 1


3) Function composition:
Allowing for concise composition of functions would be a great feature. 
E.g., instead of

foo <- function(x) print(mean(sqrt(x), na.rm = TRUE), digits = 2)

or

foo <- \x {x |> sqrt() |> mean(na.rm = TRUE) |> print(digits = 2)}

one could write

foo <- \x |> sqrt() |> mean(na.rm = TRUE) |> print(digits = 2)

So basically if the lambda argument is followed by a pipe operator, the 
pipe chain is transformed to a function body where the first lambda 
argument is inserted into the first position of the pipeline.


Best,
Denes


On 12/5/20 7:10 PM, luke-tierney at uiowa.edu wrote:
> We went back and forth on this several times. The key advantage of
> requiring parentheses is to keep things simple and consistent.? Let's
> get some experience with that. If experience shows requiring
> parentheses creates too many issues then we can add the option of
> dropping them later (with special handling of :: and :::). It's easier
> to add flexibility and complexity than to restrict it after the fact.
> 
> Best,
> 
> luke
> 
> On Sat, 5 Dec 2020, Hugh Parsonage wrote:
> 
>> I'm surprised by the aversion to
>>
>> mtcars |> nrow
>>
>> over
>>
>> mtcars |> nrow()
>>
>> and I think the decision to disallow the former should be
>> reconsidered.? The pipe operator is only going to be used when the rhs
>> is a function, so there is no ambiguity with omitting the parentheses.
>> If it's disallowed, it becomes inconsistent with other treatments like
>> sapply(mtcars, typeof) where sapply(mtcars, typeof()) would just be
>> noise.? I'm not sure why this decision was taken
>>
>> If the only issue is with the double (and triple) colon operator, then
>> ideally `mtcars |> base::head` should resolve to `base::head(mtcars)`
>> -- in other words, demote the precedence of |>
>>
>> Obviously (looking at the R-Syntax branch) this decision was
>> considered, put into place, then dropped, but I can't see why
>> precisely.
>>
>> Best,
>>
>>
>> Hugh.
>>
>>
>>
>>
>>
>>
>>
>> On Sat, 5 Dec 2020 at 04:07, Deepayan Sarkar 
>> <deepayan.sarkar at gmail.com> wrote:
>>>
>>> On Fri, Dec 4, 2020 at 7:35 PM Duncan Murdoch 
>>> <murdoch.duncan at gmail.com> wrote:
>>>>
>>>> On 04/12/2020 8:13 a.m., Hiroaki Yutani wrote:
>>>>>> ? Error: function '::' not supported in RHS call of a pipe
>>>>>
>>>>> To me, this error looks much more friendly than magrittr's error.
>>>>> Some of them got too used to specify functions without (). This
>>>>> is OK until they use `::`, but when they need to use it, it takes
>>>>> hours to figure out why
>>>>>
>>>>> mtcars %>% base::head
>>>>> #> Error in .::base : unused argument (head)
>>>>>
>>>>> won't work but
>>>>>
>>>>> mtcars %>% head
>>>>>
>>>>> works. I think this is a too harsh lesson for ordinary R users to
>>>>> learn `::` is a function. I've been wanting for magrittr to drop the
>>>>> support for a function name without () to avoid this confusion,
>>>>> so I would very much welcome the new pipe operator's behavior.
>>>>> Thank you all the developers who implemented this!
>>>>
>>>> I agree, it's an improvement on the corresponding magrittr error.
>>>>
>>>> I think the semantics of not evaluating the RHS, but treating the pipe
>>>> as purely syntactical is a good decision.
>>>>
>>>> I'm not sure I like the recommended way to pipe into a particular 
>>>> argument:
>>>>
>>>> ?? mtcars |> subset(cyl == 4) |> \(d) lm(mpg ~ disp, data = d)
>>>>
>>>> or
>>>>
>>>> ?? mtcars |> subset(cyl == 4) |> function(d) lm(mpg ~ disp, data = d)
>>>>
>>>> both of which are equivalent to
>>>>
>>>> ?? mtcars |> subset(cyl == 4) |> (function(d) lm(mpg ~ disp, data = 
>>>> d))()
>>>>
>>>> It's tempting to suggest it should allow something like
>>>>
>>>> ?? mtcars |> subset(cyl == 4) |> lm(mpg ~ disp, data = .)
>>>
>>> Which is really not that far off from
>>>
>>> mtcars |> subset(cyl == 4) |> \(.) lm(mpg ~ disp, data = .)
>>>
>>> once you get used to it.
>>>
>>> One consequence of the implementation is that it's not clear how
>>> multiple occurrences of the placeholder would be interpreted. With
>>> magrittr,
>>>
>>> sort(runif(10)) %>% ecdf(.)(.)
>>> ## [1] 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
>>>
>>> This is probably what you would expect, if you expect it to work at 
>>> all, and not
>>>
>>> ecdf(sort(runif(10)))(sort(runif(10)))
>>>
>>> There would be no such ambiguity with anonymous functions
>>>
>>> sort(runif(10)) |> \(.) ecdf(.)(.)
>>>
>>> -Deepayan
>>>
>>>> which would be expanded to something equivalent to the other versions:
>>>> but that makes it quite a bit more complicated.? (Maybe _ or \. should
>>>> be used instead of ., since those are not legal variable names.)
>>>>
>>>> I don't think there should be an attempt to copy magrittr's special
>>>> casing of how . is used in determining whether to also include the
>>>> previous value as first argument.
>>>>
>>>> Duncan Murdoch
>>>>
>>>>
>>>>>
>>>>> Best,
>>>>> Hiroaki Yutani
>>>>>
>>>>> 2020?12?4?(?) 20:51 Duncan Murdoch <murdoch.duncan at gmail.com>:
>>>>>>
>>>>>> Just saw this on the R-devel news:
>>>>>>
>>>>>>
>>>>>> R now provides a simple native pipe syntax ?|>? as well as a 
>>>>>> shorthand
>>>>>> notation for creating functions, e.g. ?\(x) x + 1? is parsed as
>>>>>> ?function(x) x + 1?. The pipe implementation as a syntax 
>>>>>> transformation
>>>>>> was motivated by suggestions from Jim Hester and Lionel Henry. These
>>>>>> features are experimental and may change prior to release.
>>>>>>
>>>>>>
>>>>>> This is a good addition; by using "|>" instead of "%>%" there 
>>>>>> should be
>>>>>> a chance to get operator precedence right.? That said, the ?Syntax 
>>>>>> help
>>>>>> topic hasn't been updated, so I'm not sure where it fits in.
>>>>>>
>>>>>> There are some choices that take a little getting used to:
>>>>>>
>>>>>> ?> mtcars |> head
>>>>>> Error: The pipe operator requires a function call or an anonymous
>>>>>> function expression as RHS
>>>>>>
>>>>>> (I need to say mtcars |> head() instead.)? This sometimes leads to 
>>>>>> error
>>>>>> messages that are somewhat confusing:
>>>>>>
>>>>>> ?> mtcars |> magrittr::debug_pipe |> head
>>>>>> Error: function '::' not supported in RHS call of a pipe
>>>>>>
>>>>>> but
>>>>>>
>>>>>> mtcars |> magrittr::debug_pipe() |> head()
>>>>>>
>>>>>> works.
>>>>>>
>>>>>> Overall, I think this is a great addition, though it's going to be
>>>>>> disruptive for a while.
>>>>>>
>>>>>> Duncan Murdoch
>>>>>>
>>>>>> ______________________________________________
>>>>>> R-devel at r-project.org mailing list
>>>>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>>>>
>>>>> ______________________________________________
>>>>> R-devel at r-project.org mailing list
>>>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>>>>
>>>>
>>>> ______________________________________________
>>>> R-devel at r-project.org mailing list
>>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>>
>>> ______________________________________________
>>> R-devel at r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>> ______________________________________________
>> R-devel at r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>



[Rd] [External] Re: New pipe operator
=?UTF-8?B?RMOpbmVzIFTDs3Ro?=