【问题标题】:How to pass a variable to a function which has already implement non-standard evaluation in its argument in R?如何将变量传递给已经在 R 的参数中实现非标准评估的函数?
【发布时间】:2022-01-05 15:17:55
【问题描述】:

我正在尝试从 R 包中封装一个函数。从源代码来看,它似乎对某些参数有非标准的评估。如何编写函数以将值传递给已实现非标准评估的参数?

这是一个玩具示例

data <- data.frame(name = 1:10)
#Suppose the one below is the function from that package
toy.fun <- function(dat, var) {
    eval(substitute(var), dat)
}
> toy.fun(data, name)
 [1]  1  2  3  4  5  6  7  8  9 10

这是我尝试包装的内容

toy.fun2 <- function(dat, var2) {
    var_name <- deparse(substitute(var2))
    #example, but for similar purpose. 
    data_subset <- dat[var_name] 
    toy.fun(data_subset, var2)
}
> toy.fun2(data, name)
 Error in eval(substitute(var), dat) : object 'var2' not found

编辑

我应该更清楚地说明这个问题,我想将不同的变量名传递给 var2 的包装器中的函数参数。因此,当数据中有不同的变量名称时,它可以使用该名称进行数据选择,并传递给我尝试包装的函数。来自heatwaveR 的exceedance 函数的源代码已经有这个 ts_y &lt;- eval(substitute(y), data) 来捕获输入变量y。这相当于我的toy.fun。

为了清楚起见,我修改了toy.fun2。

编辑 2

事实证明,解决方案非常简单,只需替换整个函数(包括参数)并对其求值。

toy.fun2 <- function(dat, var2) {
  var_name <- deparse(substitute(var2))
  #example, but for similar purpose.
  data_subset <- dat[var_name]
  exprs <- substitute(toy.fun(data_subset, var2))
  eval(exprs, parent.frame()) 
  #include `envir` argument if this is to be worked in data.table
}

【问题讨论】:

  • 非标评价就是非标。适用于toy.fun 的方法不一定适用于其他一些非标准评估。您应该指定要包装的函数。
  • 例如,@DonaldSeinen 下面的答案适用于您的示例,但可能不适用于不完全支持点参数的 tidyverse 样式的 NSE。例如。见github.com/tidyverse/glue/issues/231。
  • @user2554330 感谢您的建议。我已经修改了这个问题,希望这次能更清楚地说明问题。

标签: r function non-standard-evaluation


【解决方案1】:

使用match.call 获取调用,替换函数名称并对其进行评估。 也可以根据需要修改其他参数。查看lm 的源代码以查看此方法的另一个示例。

toy.fun2 <- function(dat, var) {
  cl <- match.call()
  cl[[1L]] <- quote(toy.fun)
  eval.parent(cl)
}
toy.fun2(data, name)
##  [1]  1  2  3  4  5  6  7  8  9 10

添加

此答案已发布后,问题已修改。这解决了新问题。行设置 cl[[2]] 也可以写成 cl[[2]] &lt;- dat[deparse(cl[[3]])] 。

toy.fun2 <- function(dat, var2) {
  cl <- match.call()
  cl[[1]] <- quote(toy.fun)
  cl[[2]] <- dat[deparse(substitute(var2))]
  names(cl)[3] <- "var"
  eval.parent(cl)
}
toy.fun2(data, name)
##  [1]  1  2  3  4  5  6  7  8  9 10

【讨论】:

  • 这不完全是我实际问题的答案,但确实给了我一个想法。我可以substitute 整个toy.fun 函数调用,里面的变量会自动被替换。评估那个表达式会给我结果。
  • eval.parent(substitute(...)) 范式基本上定义了一个宏,接口由gtools包中的defmacro函数给出。
猜你喜欢
  • 2015-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多