在给定承诺名称或形式参数的情况下评估 R 中的值
Evaluate a value in R given either the name of a promise or the formal argument
代码:
args <- function() {
list(
x = "How old",
y = "is",
z = "the car?")
}
fun1 <- function(x = "How old", y = "is", z = "the car") {
# collect arguments
args_used <- as.list(match.call()[-1])
# Call fun2() using the args supplied by the user
do.call(fun2, args_used)
}
fun2 <- function(x = args()$x, y = args()$y, z = args()$z) {
paste(x, y, z)
}
问题
使用 fun1()
and/or fun2()
如果直接使用就可以,例如
> fun1("Where", "are", z = "the cars")
[1] "Where are the cars"
但是,如果我这样做:
list1 <- list(l1 = "Where", l2 = "Is this")
list2 <- list(l1 = "is", l2 = "the")
list3 <- list(l1 = "Peter", l2 = "new iPhone?")
mapply(function(i, j, k) fun1(x = i, y = j, z = k),
i = list1,
j = list2,
k = list3,
SIMPLIFY = FALSE)
我明白了
Error in paste(x, y, z) : object 'i' not found
我知道为什么会出现问题,我什至知道如何使用 eval(parse(text = ""))
修复它(尽管我知道 eval-parse 策略的潜在问题(参见,例如:this discussion)
因此重写 fun1()
如下:
fun1 <- function(x = "How old", y = "is", z = "the car") {
# collect arguments
args_used <- as.list(match.call()[-1])
args_used <- lapply(names(args_used), function(w) eval(parse(text = w)))
# Call fun2() using the args supplied by the user
do.call(fun2, args_used)
}
并随后使用 mapply(....)
如上所述工作。
然而这里就变得棘手了。
- 注意如果我将
lapply(names(args_used), function(w) eval(parse(text = w)))
中的 w
更改为 x
会发生什么(y
和 z
也是如此。现在调用 mapply
同上,给出:
$`l1`
[1] "x is Peter"
$l2
[1] "x the new iPhone?"
Clearly not what I wanted. Again I understand why this happens and a fix would be to not use x
but something like w
but any name a pick is from now on reserved. Not ideal.
如果通过 ...
参数调用其中一个参数,该方法也会中断。像这样修改 fun1()
:
fun1 <- function(x = "How old", y = "is", ...) {
# collect arguments
args_used <- as.list(match.call()[-1])
args_used <- lapply(names(args_used), function(x) eval(parse(text = x)))
# Call fun2() using the args supplied by the user
do.call(fun2, args_used)
}
现在结果是
Error in eval(parse(text = x)) : object 'z' not found
再次,我明白为什么(因为名称 "z"
在 fun1()
环境中是未知的)但现在的问题是:
我该如何解决这个问题才能避免问题 1 和问题 2?
只需让您的函数计算调用环境中的参数即可。这似乎有效(注意添加 envir=parent.frame()
)。
fun1 <- function(x = "How old", y = "is", z = "the car") {
args_used <- as.list(match.call()[-1])
do.call(fun2, args_used, envir=parent.frame())
}
但我根本不明白你为什么要在这里使用惰性求值。您可以将所有参数捕获为环境的一部分并传递它们的值
fun1 <- function(x = "How old", y = "is", z = "the car") {
args_used <- as.list(environment())
# if you need ...: args_used <- c(as.list(environment()), list(...))
do.call(fun2, args_used)
}
请注意,environment()
将捕获您调用它时存在的所有变量。因此,如果您只需要传递给函数的变量,请务必在函数开始时调用它。
如果您的参数名称中有前导点,R 通常将它们视为 "hidden",因此您需要将 all.names=TRUE
参数设置为 as.list.environment
函数以获取它们.你可以做到
args_used <- as.list(environment(), all.names=TRUE)
代码:
args <- function() {
list(
x = "How old",
y = "is",
z = "the car?")
}
fun1 <- function(x = "How old", y = "is", z = "the car") {
# collect arguments
args_used <- as.list(match.call()[-1])
# Call fun2() using the args supplied by the user
do.call(fun2, args_used)
}
fun2 <- function(x = args()$x, y = args()$y, z = args()$z) {
paste(x, y, z)
}
问题
使用 fun1()
and/or fun2()
如果直接使用就可以,例如
> fun1("Where", "are", z = "the cars")
[1] "Where are the cars"
但是,如果我这样做:
list1 <- list(l1 = "Where", l2 = "Is this")
list2 <- list(l1 = "is", l2 = "the")
list3 <- list(l1 = "Peter", l2 = "new iPhone?")
mapply(function(i, j, k) fun1(x = i, y = j, z = k),
i = list1,
j = list2,
k = list3,
SIMPLIFY = FALSE)
我明白了
Error in paste(x, y, z) : object 'i' not found
我知道为什么会出现问题,我什至知道如何使用 eval(parse(text = ""))
修复它(尽管我知道 eval-parse 策略的潜在问题(参见,例如:this discussion)
因此重写 fun1()
如下:
fun1 <- function(x = "How old", y = "is", z = "the car") {
# collect arguments
args_used <- as.list(match.call()[-1])
args_used <- lapply(names(args_used), function(w) eval(parse(text = w)))
# Call fun2() using the args supplied by the user
do.call(fun2, args_used)
}
并随后使用 mapply(....)
如上所述工作。
然而这里就变得棘手了。
- 注意如果我将
lapply(names(args_used), function(w) eval(parse(text = w)))
中的w
更改为x
会发生什么(y
和z
也是如此。现在调用mapply
同上,给出:$`l1` [1] "x is Peter" $l2 [1] "x the new iPhone?"
Clearly not what I wanted. Again I understand why this happens and a fix would be to not use
x
but something likew
but any name a pick is from now on reserved. Not ideal. 如果通过
...
参数调用其中一个参数,该方法也会中断。像这样修改fun1()
:fun1 <- function(x = "How old", y = "is", ...) { # collect arguments args_used <- as.list(match.call()[-1]) args_used <- lapply(names(args_used), function(x) eval(parse(text = x))) # Call fun2() using the args supplied by the user do.call(fun2, args_used) }
现在结果是
Error in eval(parse(text = x)) : object 'z' not found
再次,我明白为什么(因为名称 "z"
在 fun1()
环境中是未知的)但现在的问题是:
我该如何解决这个问题才能避免问题 1 和问题 2?
只需让您的函数计算调用环境中的参数即可。这似乎有效(注意添加 envir=parent.frame()
)。
fun1 <- function(x = "How old", y = "is", z = "the car") {
args_used <- as.list(match.call()[-1])
do.call(fun2, args_used, envir=parent.frame())
}
但我根本不明白你为什么要在这里使用惰性求值。您可以将所有参数捕获为环境的一部分并传递它们的值
fun1 <- function(x = "How old", y = "is", z = "the car") {
args_used <- as.list(environment())
# if you need ...: args_used <- c(as.list(environment()), list(...))
do.call(fun2, args_used)
}
请注意,environment()
将捕获您调用它时存在的所有变量。因此,如果您只需要传递给函数的变量,请务必在函数开始时调用它。
如果您的参数名称中有前导点,R 通常将它们视为 "hidden",因此您需要将 all.names=TRUE
参数设置为 as.list.environment
函数以获取它们.你可以做到
args_used <- as.list(environment(), all.names=TRUE)