1) explicitly pass environment In general, it is safer and more flexible to pass the environment to functions using environments. One can still use parent.frame()
as the default but using an explicit argument allows the general situation to be handled.
library(magrittr)
val2 <- 10
proper_filter2 <- function(.data, ..., envir = parent.frame()) {
code <- substitute(filter(.data, ...))
print(ls(envir))
}
fn_w_magrittr2 <- function(dfr, val, .envir = environment()) {
dfr %>%
proper_filter2(speed < val, envir = .envir)
}
fn_w_magrittr2(cars, val2)
## [1] "dfr" "val"
2) formulas Another way to handle this is to use formulas since they have environments. The formula argument of proper_filter3 should be a one sided formula.
library(magrittr)
val2 <- 10
proper_filter3 <- function(.data, formula) {
code <- substitute(filter(.data, rhs), list(rhs = formula[[2]]))
print(ls(environment(formula)))
}
fn_w_magrittr3 <- function(dfr, val) {
.formula <- ~ speed < val
dfr %>%
proper_filter3(.formula)
}
fn_w_magrittr3(cars, val2)
## [1] "dfr" "val"
3) pipe_eager_lexical The magrittr package contains a pipe_eager_lexical which is currently not assigned to a infix pipe symbol. It will be defined in the next version of magrittr as seen in this commit but in the meantime we can assign it to an infix symbol ourself.
# as in question
proper_filter <- function(.data, ...) {
code = substitute(filter(.data, ...))
print(names(parent.frame()))
}
`%!>%` <- magrittr::pipe_eager_lexical # <------- note this definition
fn_w_magrittr4 <- function(dfr, val) {
dfr %!>%
proper_filter(speed < val)
}
val2 <- 10
fn_w_magrittr4(cars, val2)
## [1] "." "dfr" "val"
There is some discussion of this in the magrittr issues in https://github.com/tidyverse/magrittr/issues/171, https://github.com/tidyverse/magrittr/issues/38 and https://github.com/tidyverse/magrittr/issues/70 and it seems that they concluded that this cannot be resolved in a general way within magrittr itself without sacrificing important features of magrittr although for the problem here magrittr's eager lexical pipe is sufficient.
The above show how to handle this while still using magrittr but workarounds replacing magrittr are possible too. Another answer mentions |>
and the Bizarro pipe can be used for another workaround and not using pipes is, of course, always a possibility.