我刚才在R代码中发现了一个非常微妙的错误。以下代码将对象列表作为输入,并为每个对象创建新字段。
每个对象最初有两个字段(w,p,s,u),然后我创建更多,beta,phi等。正常变量都可以。但是动态功能(Q,K,K1,K2)不正确。假设我有两个nigs,nigs [[1]]和nigs [[2]], nigs [[1]]的函数Q,K,K1和K2与nigs [[2]]相同!
我刚刚发现了这个错误,并会就如何正确使用此代码进行咨询(同时保持其优雅:)谢谢!
D <- length(nigs)
for (i in 1:D) {
w <- nigs[[i]]$w
p <- nigs[[i]]$p
s <- nigs[[i]]$s
u <- nigs[[i]]$u
nigs[[i]]$beta <- beta <- w / s * p * (1-p^2)^(-1/2);
nigs[[i]]$phi <- phi <- w^2 / s^2;
nigs[[i]]$z <- z <- (x-u)/s;
nigs[[i]]$alpha_bar <- alpha_bar <- w * (1-p^2)^(-1/2);
nigs[[i]]$y_bar <- y_bar <- sqrt(1+z^2);
nigs[[i]]$Q <- Q <- function(t) { sqrt(1 - (2*beta*t+t^2)/phi) }
nigs[[i]]$K <- K <- function(t) { u*t - w*Q(t) + w }
nigs[[i]]$K1 <- K1 <- function(t) { (u + w * (beta+t) / (Q(t)*phi)) }
nigs[[i]]$K2 <- K2 <- function(t) { qt = Q(t); (w/(qt * phi) + w * (beta+t)^2 / (qt^3 * phi^2)); }
}
修改
我犯的主要错误是我假设for { }
引入了新的范围,在这种情况下,w,p,s,u
每次都是w,p,s,u
,实际上并非如此。只有R中的函数引入了新的范围。这个范围规则与C / Java不同。
答案 0 :(得分:6)
这是词法范围的正常行为。 你可以改用闭包。
f <- list()
g <- list()
for (i in 1:2) {
j <- i * 2
f[[i]] <- function() print(j)
g[[i]] <- (function() {j <- j; function() print(j)}) ()
}
然后,
> for (i in 1:2) f[[i]]()
[1] 4
[1] 4
> for (i in 1:2) g[[i]]()
[1] 2
[1] 4
答案 1 :(得分:6)
在面向对象的术语中,每个nigs[[i]]
都是一个对象,函数Q
,K
等是作用于对象属性的方法w
,{{1使用proto包我们将每个p
设置为一个proto对象,然后按照指示更新对象。请注意,所有方法都将对象作为第一个参数,因此如果nigs[[i]]
是包含方法p
的proto对象,那么Q
意味着在p$Q(t)
中查找p
然后使用参数Q
和p
运行它,以便t
与p$Q(t)
相同。因此,我们为下面的每个方法添加了额外的第一个参数。有关详情,请参阅proto home page。
with(p, Q(p, t))
编辑:第二种可能的设计是创建一个父对象library(proto)
# initialize
x <- 1
nigs <- lapply(1:2, function(i) proto(w = i/3, p = i/3, s = i/3, u = i/3))
for(p in nigs) with(p, {
beta <- w / s * p * (1-p^2)^(-1/2)
phi <- w^2 / s^2
z <- (x-u)/s
alpha_bar <- w * (1-p^2)^(-1/2)
y_bar <- sqrt(1+z^2)
Q <- function(., t) { sqrt(1 - (2*beta*t+t^2)/phi) }
K <- function(., t) { u*t - w*.$Q(t) + w }
K1 <- function(., t) { (u + w * (beta+t) / (.$Q(t)*phi)) }
K2 <- function(., t) {
qt = .$Q(t)
(w/(qt * phi) + w * (beta+t)^2 / (qt^3 * phi^2))
}
})
来保存方法,而不是在每个单独的proto对象中再次定义它们。在这种情况下,在每个方法中,我们必须确保使用第一个参数中传递的对象的属性,因为方法和属性现在位于不同的对象中:
meths
现在,以下工作方法是在meths <- proto(
Q = function(., t) sqrt(1 - (2*.$beta*t+t^2)/.$phi),
K = function(., t) .$u*t - .$w*.$Q(t) + .$w,
K1 = function(., t) (.$u + .$w * (.$beta+t) / (.$Q(t)*.$phi)),
K2 = function(., t) {
qt = .$Q(t)
(.$w/(qt * .$phi) + .$w * (.$beta+t)^2 / (qt^3 * .$phi^2))
}
)
# initialize - meths$proto means define proto object with parent meths
x <- 1
nigs <- lapply(1:2, function(i) meths$proto(w = i/3, p = i/3, s = i/3, u = i/3))
for(p in nigs) with(p, {
beta <- w / s * p * (1-p^2)^(-1/2)
phi <- w^2 / s^2
z <- (x-u)/s
alpha_bar <- w * (1-p^2)^(-1/2)
y_bar <- sqrt(1+z^2)
})
中查找Q
,但在其中找不到它,查看其父级nigs[[1]]
,并运行那里找到的meths
。在Q
中,调用隐式地将nigs[[1]]$Q(.1)
传递给nigs[[1]]
作为其第一个参数,并且我们已经相对于第一个参数定义了Q
体内的所有属性,因此一切正常: / p>
Q