I just checked out R-devel and noticed that the new "pipe extractor" capability coming in 4.3 only works for the 4 extractor operators, but no other standard operators like +, *, %*% etc, meaning that e.g. mtcars |> as.matrix() |> _ + 1 |> colMeans() is a syntax error. In addition, we are still subject to the restriction that the functions on the RHS of a pipe can't have special names, so mtcars |> as.matrix() |> `+`(1) |> colMeans() is also a syntax error. Either option would be great, as I find it much cleaner to coordinate a sequence of function calls using pipes rather than nested function calls or using temporary variables. May I enquire why both of these expressions are disallowed, and if it might be possible to help remove one or both of these restrictions? There is some discussion at https://stat.ethz.ch/pipermail/r-devel/2020-December/080210.html but the thread is mostly concerned with other things like the placeholder and whether or not parentheses can be omitted. My naive view is that piping into a special operator function like `+` would be the least ambiguous: `+` presumably parses to the same type of token as `colMeans` does, so the function parse tree seems like it would work fine if this was allowed in a pipe. Cheers, Michael
Generalised piping into operators
8 messages · Michael Milton, Duncan Murdoch, Dominick Samperi
On 21/04/2023 4:35 a.m., Michael Milton wrote:
I just checked out R-devel and noticed that the new "pipe extractor" capability coming in 4.3 only works for the 4 extractor operators, but no other standard operators like +, *, %*% etc, meaning that e.g. mtcars |> as.matrix() |> _ + 1 |> colMeans() is a syntax error. In addition, we are still subject to the restriction that the functions on the RHS of a pipe can't have special names, so mtcars |> as.matrix() |> `+`(1) |> colMeans() is also a syntax error. Either option would be great, as I find it much cleaner to coordinate a sequence of function calls using pipes rather than nested function calls or using temporary variables. May I enquire why both of these expressions are disallowed, and if it might be possible to help remove one or both of these restrictions? There is some discussion at https://stat.ethz.ch/pipermail/r-devel/2020-December/080210.html but the thread is mostly concerned with other things like the placeholder and whether or not parentheses can be omitted. My naive view is that piping into a special operator function like `+` would be the least ambiguous: `+` presumably parses to the same type of token as `colMeans` does, so the function parse tree seems like it would work fine if this was allowed in a pipe.
If it were allowed, people would expect expressions like yours to work, but as ?Syntax says, your pipe would actually be parsed as something like (mtcars |> as.matrix() |> _) + (1 |> colMeans()) because the |> operator has higher precedence than +. Since parens would be needed somewhere to override this, you may as well type (as.matrix(mtcars) + 1) |> colMeans() which is both shorter and arguably clearer than mtcars |> as.matrix() |> (_ + 1) |> colMeans() Duncan Murdoch
Thanks, this makes sense. Is there a similar precedence reasoning behind why operator functions (`+` etc) can't be piped into? On Fri, Apr 21, 2023 at 11:52?PM Duncan Murdoch <murdoch.duncan at gmail.com> wrote:
On 21/04/2023 4:35 a.m., Michael Milton wrote:
I just checked out R-devel and noticed that the new "pipe extractor" capability coming in 4.3 only works for the 4 extractor operators, but no other standard operators like +, *, %*% etc, meaning that e.g. mtcars |> as.matrix() |> _ + 1 |> colMeans() is a syntax error. In addition, we are still subject to the restriction that the functions on the RHS of a pipe can't have special names, so mtcars |> as.matrix() |> `+`(1) |>
colMeans() is
also a syntax error. Either option would be great, as I find it much cleaner to coordinate a sequence of function calls using pipes rather than nested function calls
or
using temporary variables. May I enquire why both of these expressions are disallowed, and if it
might
be possible to help remove one or both of these restrictions? There is
some
discussion at https://stat.ethz.ch/pipermail/r-devel/2020-December/080210.html but the thread is mostly concerned with other things like the placeholder and whether or not parentheses can be omitted. My naive view is that piping into a special operator function like `+` would be the least ambiguous:
`+`
presumably parses to the same type of token as `colMeans` does, so the function parse tree seems like it would work fine if this was allowed in
a
pipe.
If it were allowed, people would expect expressions like yours to work, but as ?Syntax says, your pipe would actually be parsed as something like (mtcars |> as.matrix() |> _) + (1 |> colMeans()) because the |> operator has higher precedence than +. Since parens would be needed somewhere to override this, you may as well type (as.matrix(mtcars) + 1) |> colMeans() which is both shorter and arguably clearer than mtcars |> as.matrix() |> (_ + 1) |> colMeans() Duncan Murdoch
On 21/04/2023 11:33 a.m., Michael Milton wrote:
Thanks, this makes sense. Is there a similar precedence reasoning behind why operator functions (`+` etc) can't be piped into?
Yes: > identical(quote(1 + 1), quote(`+`(1, 1))) [1] TRUE Duncan Murdoch
I'm afraid I don't understand. I know that parsing `+`(1, 1) returns a result equivalent to `1 + 1`, but why does that impose a restriction on parsing the pipe operator? What is the downside of allowing arbitrary RHS functions?
On 21/04/2023 12:16 p.m., Michael Milton wrote:
I'm afraid I don't understand. I know that parsing `+`(1, 1) returns a result equivalent to `1?+ 1`, but why does that impose a restriction on parsing the pipe operator? What is the downside of allowing arbitrary RHS functions?
I thought the decision to exclude "_ + 1" happens after enough parsing
has happened so that the code making the decision can't tell the
difference between "_ + 1" and "`+`(_, 1)". I might be wrong about
that, but this suggests it:
> quote(_ + 1)
Error in quote("_" + 1) : invalid use of pipe placeholder (<input>:1:0)
> quote(`+`(_, 1))
Error in quote("_" + 1) : invalid use of pipe placeholder (<input>:1:0)
On the other hand, this works:
> quote(x |> `+`(e1 = _, 1))
x + 1
So maybe `+`() is fine after all.
Duncan Murdoch
A few years ago there was a post by the author of pipeR suggesting improvements in efficiency and reliability. Is there collaboration between these various pipe projects? Sent from my iPhone
On Apr 21, 2023, at 1:01 PM, Duncan Murdoch <murdoch.duncan at gmail.com> wrote: ?On 21/04/2023 12:16 p.m., Michael Milton wrote:
I'm afraid I don't understand. I know that parsing `+`(1, 1) returns a result equivalent to `1 + 1`, but why does that impose a restriction on parsing the pipe operator? What is the downside of allowing arbitrary RHS functions?
I thought the decision to exclude "_ + 1" happens after enough parsing has happened so that the code making the decision can't tell the difference between "_ + 1" and "`+`(_, 1)". I might be wrong about that, but this suggests it:
> quote(_ + 1)
Error in quote("_" + 1) : invalid use of pipe placeholder (<input>:1:0)
> quote(`+`(_, 1))
Error in quote("_" + 1) : invalid use of pipe placeholder (<input>:1:0)
On the other hand, this works:
> quote(x |> `+`(e1 = _, 1))
x + 1 So maybe `+`() is fine after all. Duncan Murdoch
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
This is all very intriguing. Normally when piping into an operator function, R throws "Error: function '+' not supported in RHS call of a pipe":
1 |> `+`(2)
Error: function '+' not supported in RHS call of a pipe This is a different error from the above "invalid use of pipe placeholder", which makes me think it was added for a different purpose than prohibiting operator precedence issues. I am interested in the justification of this error. However, as you have noted, when using the placeholder, R has no issue with this syntax (which I didn't realise!):
1 |> `+`(x=_, 2)
[1] 3 On Sat, Apr 22, 2023 at 3:00?AM Duncan Murdoch <murdoch.duncan at gmail.com> wrote:
On 21/04/2023 12:16 p.m., Michael Milton wrote:
I'm afraid I don't understand. I know that parsing `+`(1, 1) returns a result equivalent to `1 + 1`, but why does that impose a restriction on parsing the pipe operator? What is the downside of allowing arbitrary RHS functions?
I thought the decision to exclude "_ + 1" happens after enough parsing has happened so that the code making the decision can't tell the difference between "_ + 1" and "`+`(_, 1)". I might be wrong about that, but this suggests it:
> quote(_ + 1)
Error in quote("_" + 1) : invalid use of pipe placeholder (<input>:1:0)
> quote(`+`(_, 1))
Error in quote("_" + 1) : invalid use of pipe placeholder (<input>:1:0)
On the other hand, this works:
> quote(x |> `+`(e1 = _, 1))
x + 1 So maybe `+`() is fine after all. Duncan Murdoch