From murdoch@dunc@n @end|ng |rom gm@||@com  Mon Dec  7 18:53:41 2020
From: murdoch@dunc@n @end|ng |rom gm@||@com (Duncan Murdoch)
Date: Mon, 7 Dec 2020 12:53:41 -0500
Subject: [Rd] New pipe operator
In-Reply-To: <91C38945-B1BA-4E7A-B2E0-79790A894240@gmail.com>
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>
 <CAP01uRkkd3jOjvaS9JgKYCD1KA83HfzCd+MQSv_2aYJPgcOmSQ@mail.gmail.com>
 <CAP01uRkPcbCBRGwAzKM=W19Ohh-zDGwZH8gM7=A-sK2rRaQxaQ@mail.gmail.com>
 <CAD4oTHFBY4rBhiRsJUkA6jwD2YWaxPMz2OZDOqSvHfv6A7DZPg@mail.gmail.com>
 <CAP01uRmTYna1nM+ugELHrCqLjfWuWwHSfE4cvqoaq2537sHpAw@mail.gmail.com>
 <CAD4oTHHFWkiirncPRWngY+_k9HcB=8zo7VdXAONXQoXdNhKzDA@mail.gmail.com>
 <7e28d84a-f6d0-1e18-c131-163650e7cd75@gmail.com>
 <CAP01uRkCpLQ0uwJgFdTFTNG+80C+F1hn=TnQqRS2Z-nFuU5MmA@mail.gmail.com>
 <CADfFDC74ostfecs5mhOznSXEedGBA=_78SiNTfysz5B8JU=YUQ@mail.gmail.com>
 <F7AF463A-B9A1-4AEB-9EE3-1062B6AD3CFF@gmail.com>
 <7e1eb5e9-4ee7-4a80-ad7b-58ed67c830df@gmail.com>
 <91C38945-B1BA-4E7A-B2E0-79790A894240@gmail.com>
Message-ID: <7f8cf17d-d5fa-0cd1-7760-7157ef1fe7bf@gmail.com>

On 07/12/2020 12:09 p.m., Peter Dalgaard wrote:
> 
> 
>> On 7 Dec 2020, at 17:35 , Duncan Murdoch <murdoch.duncan at gmail.com> wrote:
>>
>> On 07/12/2020 11:18 a.m., peter dalgaard wrote:
>>> Hmm,
>>> I feel a bit bad coming late to this, but I think I am beginning to side with those who want  "... |> head" to work. And yes, that has to happen at the expense of |> head().
>>
>> Just curious, how would you express head(df, 10)?  Currently it is
>>
>> df |> head(10)
>>
>> Would I have to write it as
>>
>> df |> function(d) head(d, 10)
> 
> It could be
> 
> df |> ~ head(_, 10)
> 
> which in a sense is "yes" to your question.

I think that's doing too much weird stuff.  I wouldn't want to have to 
teach it to beginners, whereas I think I could teach "df |> head(10)". 
That's doing one weird thing, but I'd count about three things I'd 
consider weird in yours.


> 
>>
>>> As I think it was Gabor points out, the current structure goes down a nonstandard evaluation route, which may be difficult to explain and departs from usual operator evaluation paradigms by being an odd mix of syntax and semantics. R lets you do these sorts of thing, witness ggplot and tidyverse, but the transparency of the language tends to suffer.
>>
>> I wouldn't call it non-standard evaluation.  There is no function corresponding to |>, so there's no evaluation at all.  It is more like the way "x -> y" is parsed as "y <- x", or "if (x) y" is transformed to `if`(x, y).
> 
> That's a point, but maybe also my point. Currently, the parser is inserting the LHS as the 1st argument of the RHS, right? Things might be simpler if it was more like a simple binop.

An advantage of the current implementation is that it's simple and easy 
to understand.  Once you make it a user-modifiable binary operator, 
things will go kind of nuts.

For example, I doubt if there are many users of magrittr's pipe who 
really understand its subtleties, e.g. the example in Luke's paper where 
1 %>% c(., 2) gives c(1,2), but 1 %>% c(c(.), 2) gives c(1, 1, 2). (And 
I could add 1 %>% c(c(.), 2, .) and  1 %>% c(c(.), 2, . + 2)  to 
continue the fun.)

Duncan Murdoch


> 
> -pd
> 
>> Duncan Murdoch
>>
>>> It would be neater if it was simply so that the class/type of the object on the right hand side decided what should happen. So we could have a rule that we could have an object, an expression, and possibly an unevaluated call on the RHS. Or maybe a formula, I.e., we could hav
>>> ... |> head
>>> but not
>>> ... |> head()
>>> because head() does not evaluate to anything useful. Instead, we could have some of these
>>> ... |> quote(head())
>>> ... |> expression(head())
>>> ... |> ~ head()
>>> ... |> \(_) head(_)
>>> possibly also using a placeholder mechanism for the three first ones. I kind of like the idea that the ~ could be equivalent to \(_).
>>> (And yes, I am kicking myself a bit for not using ~ in the NSE arguments in subset() and transform())
>>> -pd
>>>> On 7 Dec 2020, at 16:20 , Deepayan Sarkar <deepayan.sarkar at gmail.com> wrote:
>>>>
>>>> On Mon, Dec 7, 2020 at 6:53 PM Gabor Grothendieck
>>>> <ggrothendieck at gmail.com> wrote:
>>>>>
>>>>> On Mon, Dec 7, 2020 at 5:41 AM Duncan Murdoch <murdoch.duncan at gmail.com> wrote:
>>>>>> I agree it's all about call expressions, but they aren't all being
>>>>>> treated equally:
>>>>>>
>>>>>> x |> f(...)
>>>>>>
>>>>>> expands to f(x, ...), while
>>>>>>
>>>>>> x |> `function`(...)
>>>>>>
>>>>>> expands to `function`(...)(x).  This is an exception to the rule for
>>>>>> other calls, but I think it's a justified one.
>>>>>
>>>>> This admitted inconsistency is justified by what?  No argument has been
>>>>> presented.  The justification seems to be implicitly driven by implementation
>>>>> concerns at the expense of usability and language consistency.
>>>>
>>>> Sorry if I have missed something, but is your consistency argument
>>>> basically that if
>>>>
>>>> foo <- function(x) x + 1
>>>>
>>>> then
>>>>
>>>> x |> foo
>>>> x |> function(x) x + 1
>>>>
>>>> should both work the same? Suppose it did. Would you then be OK if
>>>>
>>>> x |> foo()
>>>>
>>>> no longer worked as it does now, and produced foo()(x) instead of foo(x)?
>>>>
>>>> If you are not OK with that and want to retain the current behaviour,
>>>> what would you want to happen with the following?
>>>>
>>>> bar <- function(x) function(n) rnorm(n, mean = x)
>>>>
>>>> 10 |> bar(runif(1))() # works 'as expected' ~ bar(runif(1))(10)
>>>> 10 |> bar(runif(1)) # currently bar(10, runif(1))
>>>>
>>>> both of which you probably want. But then
>>>>
>>>> baz <-  bar(runif(1))
>>>> 10 |> baz
>>>>
>>>> (not currently allowed) will not be the same as what you would want from
>>>>
>>>> 10 |> bar(runif(1))
>>>>
>>>> which leads to a different kind of inconsistency, doesn't it?
>>>>
>>>> -Deepayan
>>>>
>>>> ______________________________________________
>>>> R-devel at r-project.org mailing list
>>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>



[Rd] New pipe operator
Duncan Murdoch