问题
Relatively new to tidy evaluation and while the functions I'm making work, I want to know why different helper functions are used. For example, what is the difference between enquo
and ensym
? In the function I made below to capture daily average and moving average they're interchangeable:
library(dplyr)
library(lubridate)
library(rlang)
library(zoo)
manipulate_for_ma <- function(data, group_var, da_col_name, summary_var, ma_col_name) {
group_var <- ensym(group_var)
summary_var <- enquo(summary_var)
da_col_name <- ensym(da_col_name)
ma_col_name <- enquo(ma_col_name)
data %>%
group_by(!!group_var) %>%
summarise(!!da_col_name := mean(!!summary_var, na.rm = TRUE)) %>%
mutate(!!ma_col_name := rollapply(!!da_col_name,
30,
mean,
na.rm = TRUE,
partial = TRUE,
fill = NA)) %>%
rename(date = !!group_var)
}
lakers %>%
mutate(date = ymd(date)) %>%
manipulate_for_ma(group_var = date,
da_col_name = points_per_play_da,
summary_var = points,
points_per_play_ma)
# A tibble: 78 x 3
date points_per_play_da points_per_play_ma
<date> <dbl> <dbl>
1 2008-10-28 0.413 0.458
2 2008-10-29 0.431 0.459
3 2008-11-01 0.408 0.456
4 2008-11-05 0.386 0.457
I've read about enquo
here and ensym
(here)[https://adv-r.hadley.nz/quasiquotation.html]. Is the difference that ensym
is more restrictive and only takes strings or string-like objects?
回答1:
Another take :
library(rlang)
library(dplyr, warn.conflicts = FALSE)
test <- function(x){
Species <- "bar"
cat("--- enquo builds a quosure from any expression\n")
print(enquo(x))
cat("--- ensym captures a symbol or a literal string as a symbol\n")
print(ensym(x))
cat("--- evaltidy will evaluate the quosure in its environment\n")
print(eval_tidy(enquo(x)))
cat("--- evaltidy will evaluate a symbol locally\n")
print(eval_tidy(ensym(x)))
cat("--- but both work fine where the environment doesn't matter\n")
identical(select(iris,!!ensym(x)), select(iris,!!enquo(x)))
}
Species = "foo"
test(Species)
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^Species
#> env: global
#> --- ensym captures a symbol or a literal string as a symbol
#> Species
#> --- evaltidy will evaluate the quosure in its environment
#> [1] "foo"
#> --- evaltidy will evaluate a symbol locally
#> [1] "bar"
#> --- but both work fine where the environment doesn't matter
#> [1] TRUE
test("Species")
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^"Species"
#> env: empty
#> --- ensym captures a symbol or a literal string as a symbol
#> Species
#> --- evaltidy will evaluate the quosure in its environment
#> [1] "Species"
#> --- evaltidy will evaluate a symbol locally
#> [1] "bar"
#> --- but both work fine where the environment doesn't matter
#> [1] TRUE
test(paste0("Spec","ies"))
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^paste0("Spec", "ies")
#> env: global
#> --- ensym captures a symbol or a literal string as a symbol
#> Only strings can be converted to symbols
Created on 2019-09-23 by the reprex package (v0.3.0)
回答2:
Here is one example illustrating one difference (namely that enquo
captures the calling environment and ensym
doesn't). Hopefully it speaks for itself:
library(rlang)
f <- function(x) {
foo <- 42
print(eval_tidy(quo(!! ensym(x))))
print(eval_tidy(quo(!! enquo(x))))
}
foo <- 3
f(foo)
# [1] 42
# [1] 3
Or the slightly more convoluted:
library(rlang)
myenv <- new.env()
local(envir = myenv, {
foo <- 17
g <- function(x) {
print(eval_tidy(quo(!! ensym(x))))
print(eval_tidy(quo(!! enquo(x))))
}
})
foo <- 123
myenv$g(foo)
#> [1] 17
#> [1] 123
Created on 2019-09-18 by the reprex package (v0.3.0)
The difference is often not noticeable when using dplyr since it is foolproof enough to always look up names in the context of the .data
argument first.
来源:https://stackoverflow.com/questions/57960245/what-is-the-difference-between-ensym-and-enquo-when-programming-with-dplyr