R,函数内的值传递

Posted

技术标签:

【中文标题】R,函数内的值传递【英文标题】:R, pass-by-value inside a function 【发布时间】:2015-07-02 02:23:59 【问题描述】:

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

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

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

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

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

我想创建一个有 N 个人的“社会”,即 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 获得的是价值传递,因此每个人都获得了适量的财富。但是 A 是按引用传递的——每个人都被分配了相同的函数 u(即使用 i = N 的函数)

为了完成它,接下来的步骤是获得社会,并通过两次优化获得一个“平衡点”。

【问题讨论】:

【参考方案1】:

您可以创建一个使用锁定绑定的函数并创建一个函数来完成您的目的。之前的 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(参见 cmets)

编辑:小心:如果你调用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 &lt;- 等。该函数将在声明后立即返回,因为您希望它类似于链接中定义的代码工厂。

由 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)

【讨论】:

当然,如果w 被重新分配,我们就有问题了。与其说是解决问题,不如把它放在可能没人注意到的角落里。 问题陈述让我相信(而且我仍然相信)该函数在定义时只需要 a 的值。如果 OP 重新定义函数,这意味着他们想要 a 的新值,依此类推。 w 只能通过再次调用create.func 来更改,换句话说,在他的问题中,这相当于重新定义函数 通过在全局环境中简单地重新分配w 可以更改。不仅在致电create.func 时。 f(1);w&lt;-2222;f(1) 给出两个单独的答案。这对我来说有点荒谬,因为您的解决方案显然是问题的答案。我在考虑重新分配到特定环境 j&lt;-new.env();j$w&lt;-a 可以防止此类问题。 非常感谢,它似乎正在运行 - 我正在运行您的代码(以及您之前发布的代码)。我认为 R 中会有一些简单的命令可以解决问题(eval、force 或类似的东西)。但我想在 R 中做到这一点并不是那么简单。如果我有足够的代表,我会投票并勾选你的答案。 谢谢,我刚刚编辑了我的答案,create.func 显然不需要争论,这对我来说很愚蠢。请注意,如果您再次为另一个变量调用create.funcf 也会发生变化,尽管看起来不应该这样做。如果这不是您想要的行为,请告诉我【参考方案2】:

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

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

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

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

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

【讨论】:

谢谢 - 我想避免向函数添加新参数(例如,如果我试图找到函数的零点,我必须让 R 知道我正在修复一个给定的值——因为我正在处理一个列表,所以我将使用 lapply,但我不确定我是否知道如何通知 R 在 lapply 中使用正确的参数 a)。 @JJO:lapply() 仍然非常简单,因为它支持传递给输入函数的更多参数。请参阅我对答案的补充。 非常感谢,亚历克斯。我认为你是对的,也许我应该绕过建立一个“社会”,而只是对 W 和 A 矩阵使用一些 lapply - 将尝试在这个方向重新考虑代码。如果可行,那肯定是最快的选择。 @JJO:我不确定您所说的“社会”是什么意思,但如果这个答案充分解决了您的问题,您可以将其标记为已接受。 (或其他答案之一——以最适合您的为准。) 嗨,Alex,我没有足够的代表来投票或接受。我仍在试图弄清楚如何最好地解决这个问题 - 似乎这个问题与 R 中的“工厂函数”有关。【参考方案3】:

f 中定义a

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

【讨论】:

感谢您的回答。在我的情况下它不起作用,因为我正在循环 a(我正在创建一个依赖于参数 a 的函数列表 - 所以,我不能在函数 f 内重新定义 a) 您能否在您的帖子中提供更具代表性的示例,以便我们提供合适的解决方案。谢谢 @JJO 所以你想要这种行为?这一直让我觉得是 r 中的一个“陷阱”。您应该明确将变量传递给函数

以上是关于R,函数内的值传递的主要内容,如果未能解决你的问题,请参考以下文章

java中的值传递和引用传递

Java 值传递和引用传递

值传递和引用传递的区别

按名称传递参数

java的值传递机制

在 TapBarController 内的 ViewController 和 NavigationController 之间传递值