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)


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).

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.sar...@gmail.com> wrote:

On Mon, Dec 7, 2020 at 6:53 PM Gabor Grothendieck
<ggrothendi...@gmail.com> wrote:

On Mon, Dec 7, 2020 at 5:41 AM Duncan Murdoch <murdoch.dun...@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@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to