【问题标题】:When to use rlang::ensym() over rlang::sym()?何时在 rlang::sym() 上使用 rlang::ensym()?
【发布时间】:2018-08-18 21:29:03
【问题描述】:

我可以从文档中看到rlang::enquo()rlang::quo() 在不同的上下文中使用。因此,我最近在函数声明中使用了rlang::enysm()(见下文)。但是,包裹在另一个 SE 函数调用中时,我遇到了一个意外错误,我猜这与惰性评估有关(如果我在 f_enysm() 中使用 force(x),该错误就会消失)。但似乎我也可以通过简单地使用sym(x) 而不是ensym(x) 来解决这个问题,因为x 是一个不传达任何有关环境信息的字符串(而不是quosures)。

这样安全吗?

如果是,我不知道什么时候我应该更喜欢 ensym() 而不是 sym 并且建议的使用似乎与 quo() / enquo()expr() / enexpr() 等使用的术语不一致。

library(rlang)
f_ensym <- function(data, x, fun) {
  x <- fun(x)
  head(dplyr::arrange(data, !!x))
}
f_ensym(mtcars, "cyl", sym)
#>    mpg cyl  disp hp drat    wt  qsec vs am gear carb
#> 1 22.8   4 108.0 93 3.85 2.320 18.61  1  1    4    1
#> 2 24.4   4 146.7 62 3.69 3.190 20.00  1  0    4    2
#> 3 22.8   4 140.8 95 3.92 3.150 22.90  1  0    4    2
#> 4 32.4   4  78.7 66 4.08 2.200 19.47  1  1    4    1
#> 5 30.4   4  75.7 52 4.93 1.615 18.52  1  1    4    2
#> 6 33.9   4  71.1 65 4.22 1.835 19.90  1  1    4    1


f_sym <- function(data, x) {
  x <- sym(x)
  head(dplyr::arrange(data, !!x))
}

g <- function(data, x, fun) {
  fun(data, x)
}

g(mtcars, "cyl", f_ensym)
#> Error in fun(x): argument "fun" is missing, with no default
g(mtcars, "cyl", f_sym)
#>    mpg cyl  disp hp drat    wt  qsec vs am gear carb
#> 1 22.8   4 108.0 93 3.85 2.320 18.61  1  1    4    1
#> 2 24.4   4 146.7 62 3.69 3.190 20.00  1  0    4    2
#> 3 22.8   4 140.8 95 3.92 3.150 22.90  1  0    4    2
#> 4 32.4   4  78.7 66 4.08 2.200 19.47  1  1    4    1
#> 5 30.4   4  75.7 52 4.93 1.615 18.52  1  1    4    2
#> 6 33.9   4  71.1 65 4.22 1.835 19.90  1  1    4    1

# If I remove one level, I don't get the problematic behaviour.
f <- function(data, x, fun) {
  x <- fun(x)
  head(dplyr::arrange(data, !!x))
}
f(mtcars, "cyl", sym)
#>    mpg cyl  disp hp drat    wt  qsec vs am gear carb
#> 1 22.8   4 108.0 93 3.85 2.320 18.61  1  1    4    1
#> 2 24.4   4 146.7 62 3.69 3.190 20.00  1  0    4    2
#> 3 22.8   4 140.8 95 3.92 3.150 22.90  1  0    4    2
#> 4 32.4   4  78.7 66 4.08 2.200 19.47  1  1    4    1
#> 5 30.4   4  75.7 52 4.93 1.615 18.52  1  1    4    2
#> 6 33.9   4  71.1 65 4.22 1.835 19.90  1  1    4    1
f(mtcars, "cyl", ensym)
#>    mpg cyl  disp hp drat    wt  qsec vs am gear carb
#> 1 22.8   4 108.0 93 3.85 2.320 18.61  1  1    4    1
#> 2 24.4   4 146.7 62 3.69 3.190 20.00  1  0    4    2
#> 3 22.8   4 140.8 95 3.92 3.150 22.90  1  0    4    2
#> 4 32.4   4  78.7 66 4.08 2.200 19.47  1  1    4    1
#> 5 30.4   4  75.7 52 4.93 1.615 18.52  1  1    4    2
#> 6 33.9   4  71.1 65 4.22 1.835 19.90  1  1    4    1

另外,如果我删除中间函数 f_sym()f_enysm() 并直接调用 f(),我不会得到探测行为。

f <- function(data, x, fun) {
  x <- fun(x)
  head(dplyr::arrange(data, !!x))
}
f(mtcars, "cyl", sym)
#>    mpg cyl  disp hp drat    wt  qsec vs am gear carb
#> 1 22.8   4 108.0 93 3.85 2.320 18.61  1  1    4    1
#> 2 24.4   4 146.7 62 3.69 3.190 20.00  1  0    4    2
#> 3 22.8   4 140.8 95 3.92 3.150 22.90  1  0    4    2
#> 4 32.4   4  78.7 66 4.08 2.200 19.47  1  1    4    1
#> 5 30.4   4  75.7 52 4.93 1.615 18.52  1  1    4    2
#> 6 33.9   4  71.1 65 4.22 1.835 19.90  1  1    4    1
f(mtcars, "cyl", ensym)
#>    mpg cyl  disp hp drat    wt  qsec vs am gear carb
#> 1 22.8   4 108.0 93 3.85 2.320 18.61  1  1    4    1
#> 2 24.4   4 146.7 62 3.69 3.190 20.00  1  0    4    2
#> 3 22.8   4 140.8 95 3.92 3.150 22.90  1  0    4    2
#> 4 32.4   4  78.7 66 4.08 2.200 19.47  1  1    4    1
#> 5 30.4   4  75.7 52 4.93 1.615 18.52  1  1    4    2
#> 6 33.9   4  71.1 65 4.22 1.835 19.90  1  1    4    1

【问题讨论】:

  • 刚刚看到您更新的示例。如果您查看该函数,当您运行 g 时,fun 因为它是 f_ensym 并且我可以在您的参数中找到,没有 'sym' 或 ensym 被用作输入它来处理
  • ensym() 允许您的函数的用户提供不带引号的名称。此外,它接受字符串,因为它旨在模仿参数的语法,您可以在 LHS 中同时提供这两个参数,例如list(bare = 1, "quoted" = 2)
  • @lionel 我只是想知道您如何评估g(mtcars, "cyl", f_ensym, ensym)(以下解决方案),因为fun(x) 在函数内返回x 而不是cyl。我试过!!,如果你有更好的解决方案,请发帖
  • 您需要取消引用 !!。不知道这个高阶函数有什么应用,好像有点绕。

标签: r rlang tidyeval


【解决方案1】:

ensym 可以接受带引号和不带引号的参数

f_ensym(mtcars, "cyl")
f_ensym(mtcars, cyl)

根据 OP 帖子中的更新示例,sym 采用字符串对象 g 仅采用三个参数,而 fun 的一部分是 'f_ensymwhich also have afun`被传入。我们可以为此再提出一个论据

g <- function(data, x, fun, fun2) {
     fun(data, x, fun2)
  }

g(mtcars, "cyl", f_ensym, sym)
#   mpg cyl  disp hp drat    wt  qsec vs am gear carb
#1 22.8   4 108.0 93 3.85 2.320 18.61  1  1    4    1
#2 24.4   4 146.7 62 3.69 3.190 20.00  1  0    4    2
#3 22.8   4 140.8 95 3.92 3.150 22.90  1  0    4    2
#4 32.4   4  78.7 66 4.08 2.200 19.47  1  1    4    1
#5 30.4   4  75.7 52 4.93 1.615 18.52  1  1    4    2
#6 33.9   4  71.1 65 4.22 1.835 19.90  1  1    4    1

【讨论】:

  • 好的,谢谢,所以如果我想避免在任何情况下引用并且知道输入是字符串或指向字符串的变量,我认为在函数声明中使用sym() 会更安全,对吧?
  • @LorenzWalthert 如果输入始终是字符串,则可以使用sym
猜你喜欢
  • 2019-12-11
  • 1970-01-01
  • 2019-02-04
  • 2019-01-24
  • 2022-01-08
  • 2021-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多