base R 将参数的名称替换为函数调用

base R substitute names of the arguments to function call

问题的最终目标是使用对语言的计算构造以下未评估调用,其中lista_name50L 由参数提供。

list(a_name = 50L)

内部看起来像

str(quote(list(a_name = 50L)))
# language list(a_name = 50L)

str(as.list(quote(list(a_name = 50L))))
#List of 2
# $       : symbol list
# $ a_name: int 50

我会将我的变量放在一个列表中,这样以后的代码会更清晰。

params = list(my_fun = as.name("list"), my_name = "a_name", my_value = 50L)

# What I tried so far?

# 1. The first thing that one would try

substitute(my_fun(my_name = my_value),
           params)
#list(my_name = 50L) ## `my_name` was not substituted!

# 2. Workaround get the same output, but only after `setNames` call evaluation, so doesn't really answer the question about constructing specific call

substitute(setNames(my_fun(my_value), my_name), ## alternatively could be `structure(..., names=my_name)`
           params)
#setNames(list(50L), "a_name")

# 3. Another workaround, not really computing on the language but parsing, and integer L suffix is gone!

with(expr = parse(text=paste0(my_fun, "(", my_name, " = ", my_value, ")"))[[1L]],
     data = params)
#list(a_name = 50)

# 4. Working example using rlang

with(expr = rlang::call2(my_fun, !!my_name := my_value),
     data = params)
#list(a_name = 50L)

在 base 中有什么方法可以构建所需的调用吗? 基本上是为了获得与 rlang 完全相同的输出,但使用 base .

请注意,此问题不是 的重复,后者严格要求 rlang 解决方案。这个问题要求一种使用基 来实现它的方法。如果没有办法实现它,我也想知道。谢谢。

假设问题是如何生成一个call对象,其功能是params的第一个参数,其单个参数名称是params的第二个组件的值并且其参数值是 params 的第三个组件,那么 c2 就是那个调用对象。我们验证生成的 cakl 对象与问题中显示的 rlang 调用对象相同。

c2 <- as.call(setNames(params, c("", "", params2$my_name))[-2])

# verify that c2 equals the output of the rlang example in question
c1 <- with(expr = rlang::call2(my_fun, !!my_name := my_value), data = params)

identical(c1, c2)
## [1] TRUE

这概括地说,如果调用有更多参数,使 params 的长度为 n+2,并且 params 的第二个组成部分是长度为 n 的名称向量,那么它仍然有效。

如果您可以控制输入,我认为将输入列表定义为具有函数名称的一个组件和每个参数的一个组件更有意义,组件的名称是参数名称(如反对一个单独的参数来保存名称)。在那种情况下,我们可以简单地编写以下内容。实际上,上面所做的是将参数转换为该形式,然后使用 as.call 所以我们最好从一开始就提供该形式。

as.call(params2)  # params2[[1]] is func name, params2[-1] is named args

备注

要执行调用,只需使用:

eval(c2)

或者我们可以使用 do.call:

do.call(as.character(params[[1]]), setNames(tail(params, -2), params[[2]]))