R,函数内的按值传递

R, pass-by-value inside a function

假设您使用以下代码在 R 中定义一个函数:

a <- 1
f <- function(x) x + a

如果您稍后重新定义 a,您将更改函数 f。 (所以,f(1) = 2 是给定的,但如果你稍后重新定义 a =2,那么 f(1) = 3。有没有办法强制 R 在编译时使用 a 的值函数?(也就是说,f 不会随着 a 的后期重新定义而改变)。

以上是我能想到的最短的情况,体现了我遇到的问题。更具体地说,应要求,我的情况是:

我正在处理我正在调用的一堆对象 "person"。每个人都被定义为一个概率分布,该分布取决于一个 n 维向量 $a$ 和一个 n 维约束向量 w(财富份额)。

我想创建一个有 N 个人的 "society",即 N 个人的列表。为此,我创建了两个 n×N 矩阵 A 和 W。我现在循环 1 到 N 来创建个体。

Society <- list()

### doesn't evaluate theta at the time, but does w...
for (i in 1:Npeople) {
   w <- WealthDist[i,]
   u <- function(x)  prod(x^A[i,]) 

   P <- list(u,w)
   names(P) <- c("objective","w")
   Society[[length(Society)+1]] <- P

}

w gets 是按价值传递的,因此每个人都获得了适量的财富。但是 A 是按引用传递的——每个人都被分配了相同的函数 u(即使用 i = N 的函数)

为了完成它,接下来的步骤是获得协会,并通过两次优化获得 "equilibrium point"。

f

内定义 a
f <- function(x) {a<-1;x + a}

R 不通过引用传递;一切都按值传递给函数。正如您所注意到的,由于 a 是在全局环境中定义的,因此引用 a 的函数引用的是 a 的全局值,该值可能会发生变化。为确保使用a的特定值,您可以将其用作函数中的参数。

f <- function(x, a = 1) {
    x + a
}

这将a定义为默认为1的参数。函数使用的a的值将始终是传递给函数的值,无论a 在全局环境中定义。

如果您要使用 lapply(),只需将 a 作为参数传递给 lapply()

lapply(X, f, a = <value>)

您可以创建一个使用锁定绑定的函数,并创建一个函数来完成您的目的。 a 的前值将用于 w,它将存储在函数的环境中,并且不会被 a.

的进一步值更改所取代
a <- 1
j <- new.env() # create a new environment
create.func <- function () {
  j$w <<- a
  function (x) {
    x+ j$w
  }
}
f <- create.func() 
a <- 2
f(2)
[1] 3 # if w was changed this should be 4

致谢 Andrew Taylor(见评论)

编辑: 注意:如果你调用 create.func,f 会改变,即使你没有将它存储到 f 中。为避免这种情况,您可以编写此代码(这显然取决于您想要什么)。

a <- 1
create.func <- function (x) {
  j <- new.env()
  j$w <- a
  function (x) {
    x + j$w
  }
}
f <- create.func()
f(1)
[1] 2
a <- 2
q <- create.func()
q(1)
[1] 3
f(1)
[1] 2

编辑 2: 延迟求值不适用于此处,因为 a 是通过设置为 j$w 来求值的。如果您将其用作参数,请说:

function(a)
   function(x)
     #use a here

您必须在定义第二个函数之前使用 force,因为那样它就不会被计算。

编辑 3: 我删除了 foo <- 等。该函数将在声明后立即 return,因为您希望它相似到您的 link.

中定义的代码工厂

由 OP 编辑​​只是为了添加到已接受的答案中,本着 Function Factory in R 下面的代码有效:

funs.gen <- function(n) {
  force(n)
  function(x) {
    x + n
  }  
}

funs = list()
for (i in seq(length(names))) {
   n = names[i]
   funs[[n]] = funs.gen(i)
}