如何将变量传递给已经在 R 的参数中实现非标准评估的函数?

Posted

技术标签:

【中文标题】如何将变量传递给已经在 R 的参数中实现非标准评估的函数?【英文标题】:How to pass a variable to a function which has already implement non-standard evaluation in its argument in 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 的包装器中的函数参数。因此,当数据中有不同的变量名称时,它可以使用该名称进行数据选择,并传递给我尝试包装的函数。来自heatwaveRexceedance 函数的源代码已经有这个 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 感谢您的建议。我已经修改了这个问题,希望这次能更清楚地说明问题。 【参考方案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函数给出。

以上是关于如何将变量传递给已经在 R 的参数中实现非标准评估的函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何将变量传递给评估函数?

如何在尚未对其进行评估的情况下将变量传递给自定义组件?

如何将实例变量传递给打字稿装饰器参数?

在 R 中,如何将参数作为字符串传递给像 plotXtabs2 这样的函数?

如何使用 C++/CLI Wrapper 将变量参数从托管传递到非托管?

传递给 onclick 函数的 blazor 变量参数 [重复]