问题描述
我正试图解决我遇到的一个问题,我认为它主要围绕环境、惰性评估和与这些事情相关的问题。我有一个主要功能(foo1
下面),在我的实际用例中非常广泛。出于这个原因,我试图提供一些包装函数(foo2
和 foo3
)来修改主函数的特定元素。
我的问题是我最终没有获得实际值,而是获得了符号。有人可以提供一些指导,说明我需要对环境进行哪些操作,哪些不能进行排序?
这是我的 MWE:
foo1 <- function(foo,a,b,c=1,d=1) {
if (!missing(foo)) {
mcall <- as.list(match.call())[-(1:2)]
call_names <- names(mcall)
foo <- foo[-which(names(foo) %in% call_names)]
foo <- c(foo,mcall)
} else {
foo <- list(a=a,b=b,c=c,d=d)
}
return(foo)
}
foo2 <- function(a,b) {
foo1(a=a,b=b)
}
foo3 <- function(foo,c,d) {
foo1(foo,d=d)
}
f <- foo2(a=1,b=1)
f <- foo3(f,c=2,d=2)
str(f)
> str(f)
List of 4
$ a: num 1
$ b: num 1
$ c: symbol c
$ d: symbol d
这里我希望 c
和 d
等于 2
,但它们是符号。
解决方法
当您使用 match.call
时,它会阻止对参数进行评估。如果要评估参数,则需要明确执行此操作。例如
foo1 <- function(foo,a,b,c=1,d=1) {
if (!missing(foo)) {
mcall <- as.list(match.call())[-2]
mcall[[1]] <- quote(list)
mcall <- eval(as.call(mcall))
call_names <- names(mcall)
foo <- foo[-which(names(foo) %in% call_names)]
foo <- c(foo,mcall)
} else {
foo <- list(a=a,b=b,c=c,d=d)
}
return(foo)
}
这会将调用 foo1
变为调用 list()
并评估结果。另一种选择是将 mget()
与您想要捕获的本地环境中的变量一起使用。这将触发评估
foo1 <- function(foo,d=1) {
if (!missing(foo)) {
mlist <- mget(intersect(setdiff(ls(),"foo"),names(match.call())))
call_names <- names(mlist)
foo <- foo[-which(names(foo) %in% call_names)]
foo <- c(foo,mlist)
} else {
foo <- list(a=a,d=d)
}
return(foo)
}