2

I'm trying to understand how |> works, and how it compares to the magrittr %>%. Consider the following code, which is rather unpleasant to look at / debug:

toy <- data.frame(a = c(1,2,3), type = c("apple", "pear", "orange"))

set.seed(1)
subset(toy, type == "apple")[sample(nrow(subset(toy, type == "apple")), 1),]
#>   a  type
#>   1 1 apple

The documentation of |> says:

Pipe notation allows a nested sequence of calls to be written in a way that may make the sequence of processing steps easier to follow.

Which makes me believe something like

toy |>
  subset(type == "apple") |>
  `[.data.frame`(sample(nrow(.), 1),)

is possible, but doesn't work, as the dot is meaningless here. Note, [.data.frame seems to bypass the [ restriction of the RHS of |>. I've tried to find the source code for |> by running *backtick*|>*backtick* in the console, but that results in Error: object '|>' not found.

Using the magrittr pipe, a placeholder . can be used like this:

library(magrittr)
toy %>%
  subset(type == "apple") %>%
  `[`(sample(nrow(.), 1),)
#>   a  type
#>   1 1 apple

Question

How to properly write nested calls using base R pipe |>?

Donald Seinen
  • 3,632
  • 1
  • 7
  • 27
  • `toy |> subset(type == "apple") |> {\(.) ``[.data.frame``(sample(nrow(.), 1),)}()` – Eyayaw Nov 06 '21 at 09:20
  • @Eyayaw Use of `{` results in an error: `toy |> {}` >> `{ is not supported in RHS of |>` – Donald Seinen Nov 06 '21 at 09:26
  • 1
    `toy |> subset(type == "apple") |> (function(x) {x[sample(nrow(x), 1), ]})()` – phiver Nov 06 '21 at 09:29
  • It works for me. Try this example: `mtcars|> subset(am == 1) |> {\(.) ``[.data.frame``(., sample(nrow(.), 1), )}()` – Eyayaw Nov 06 '21 at 09:31
  • 1
    There is no source code for `|>`. Unlike `%>%`, it is not an operator in that sense. It is handled completely by the parser. You can see this if you do something like `deparse(quote(toy |> subset(type == "apple")))`, which gives `"subset(toy, type == \"apple\")"`. – user2554330 Nov 06 '21 at 12:43
  • @user2554330 Ah, that's clearer than *"syntax transformation"* mentioned in the help file. So I shouldn't expect the placeholder `=>` to behave anything like magrittr's `.` placeholder (yet) if I want to refer to anything other than the top level in RHS. – Donald Seinen Nov 06 '21 at 14:59
  • base R native pipe `|>` now have a placeholder, `_`. See [here](https://stackoverflow.com/a/72004083/13460602). – Maël Apr 25 '22 at 18:35

1 Answers1

2
toy <- data.frame(a = c(1,2,3), type = c("apple", "pear", "orange"))

set.seed(1)

toy |> subset(type == "apple") |> 
(\(x) x[sample(nrow(x), 1), ])()
 a  type
1 1 apple

toy |> subset(type == "apple") |> 
(\(x) `[.data.frame`(x, sample(nrow(x), 1), ))()
 a  type
1 1 apple
Eyayaw
  • 901
  • 4
  • 9
  • Constructing and calling an anonymous function does work, thanks for the answer. Would it be correct to say "the base R pipe does not support placeholder arguments natively, but they can be constructed by formulating and calling anonymous functions"? Also - I'm a bit confused why `(` after `|>` does not throw an error. both `(` and `function` are not supported as RHS independently, but used together it works – Donald Seinen Nov 06 '21 at 10:03
  • 1
    Yes, as of now, the base pipe Op does not support a placeholder. There is an experimental placeholder option that you can turn on with `Sys.setenv`. Please look at [this](https://stackoverflow.com/a/67821421/9782217) SO answer. You can use `{` or `(` as a delimiter interchangeably. – Eyayaw Nov 06 '21 at 10:43