简短版本
具有两个变量 x
和 y
的表达式,其中 x
包含在环境 1 中y
包含在第二个环境中。 程序员如何评估表达?
详细版本
我有一个函数,它将formula
和数据帧作为参数。 在formula
的右侧是对函数的调用 splines::bs
生成 B 样条基础。 主力功能做了几件事,其中之一这需要从公式中提取bs
调用并对其进行评估。 这我试图解决的问题涉及在参数时评估bs
调用值包含在不同的环境中。
以下是重现我正在处理的问题所需的函数
library(splines)
extract_bmat <- function(form) {
B <- NULL
rr <- function(x) {
if (is.call(x) && grepl("bs", deparse(x[[1]]))) {
B <<- x
} else if (is.recursive(x)) {
as.call(lapply(as.list(x), rr))
} else {
x
}
}
z <- lapply(as.list(form), rr)
B
}
some_workhorse <- function(formula, data) {
# ... lots of cool stuff ...
# fit <- lm(formula, data)
bmat <- eval(extract_bmat(formula), data)
bmat
}
# The following works when evaluated in the .GlobalEnv
# The eval(extract_bmat(formula), data) call within the some_workhorse
# function works without errors
xi <- c(3, 4.5)
eg_data <- data.frame(x = 1:10, y = sin(1:10))
some_workhorse(y ~ bs(x, knots = xi), data = eg_data)
现在,如果函数some_workhorse
并且xi
向量和eg_data
在函数环境中生成的data.frame
会导致错误。
foo <- function() {
xi_in_foo <- c(2, 3)
eg_data_in_foo <- data.frame(x = 1:10, y = sin(1:10))
some_workhorse(y ~ bs(x, knots = xi_in_foo), data = eg_data_in_foo)
}
foo()
# Error in sort(c(rep(Boundary.knots, ord), knots)) :
# object 'xi_in_foo' not found
错误的位置在splines::bs
调用内,但这不是重要部分; 未找到xi_in_foo
是要解决的重要问题。
我知道这个问题与我在 R 中对环境的处理不当有关。 我主要问题是
eval(extract_bmat(formula), data)
呼叫应该如何在 编写some_workhorse
函数,使其在调用时正常工作.GlobalEnv
还是何时在函数环境中调用?
次要问题:
- 在
extract_bmat
函数中,我更愿意定义一个环境用于B
并使用assign
而不是<<-
。 我怀疑<<-
是最好的选项,因为发生的递归水平存在不确定性。也就是说,我希望看到其他解决方案。
感谢您的帮助。
你应该将你的函数定义为
some_workhorse <- function(formula, data) {
# ... lots of cool stuff ...
# fit <- lm(formula, data)
bmat <- eval(extract_bmat(formula), data, environment(formula))
bmat
}
请注意,R 中的formula
捕获创建它们的环境。只要定义公式的环境中存在xi_in_foo
,这应该有效。变量将首先在data
列表/data.frame 中查找,然后将公式环境用作封闭环境。如果您不使用公式,有时人们使用 parent.frame()
作为 enclos=
参数,以便在调用函数的环境中查找变量,而不是将函数定义为 R 词法范围的默认值。