在R中创建动态函数的错误

时间:2012-01-30 10:36:37

标签: r

我刚才在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不同。

2 个答案:

答案 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]]都是一个对象,函数QK等是作用于对象属性的方法w,{{1使用proto包我们将每个p设置为一个proto对象,然后按照指示更新对象。请注意,所有方法都将对象作为第一个参数,因此如果nigs[[i]]是包含方法p的proto对象,那么Q意味着在p$Q(t)中查找p然后使用参数Qp运行它,以便tp$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