应用系列功能的范围如何?

J. *_*ini 5 scope r apply replicate

考虑:

x <- 5
replicate(10, x <- x + 1)
Run Code Online (Sandbox Code Playgroud)

这有输出c(6, 6, 6, 6, 6, 6, 6, 6, 6, 6)。然而:

x <- 5
replicate(10, x <<- x + 1)
Run Code Online (Sandbox Code Playgroud)

有输出c(6, 7, 8, 9, 10, 11, 12, 13, 14, 15)

这对x <- x + 1被评估的环境意味着什么?我是否相信它x被视为内部变量replicate?这似乎是我所看到的,但是当我查阅语言定义的相关部分时,我看到了以下内容:

还值得注意的是,如果参数被求值,foo(x <- y) 的效果是在调用环境中而不是在 foo 的求值环境中更改 x 的值。

但如果x真的是在调用环境中改变了,那为什么会:

x <- 5
replicate(10, x <- x + 1)
x
Run Code Online (Sandbox Code Playgroud)

返回5与否15?我误解了哪一部分?

use*_*330 5

您从语言定义中引用的句子是关于标准评估的,但replicate使用了非标准评估。这是它的来源:

replicate <- function (n, expr, simplify = "array") 
sapply(integer(n), eval.parent(substitute(function(...) expr)), 
    simplify = simplify)
Run Code Online (Sandbox Code Playgroud)

substitute(function(...) expr)调用接受你的表达x <- x + 1没有评估它,并创建一个新的功能

function(...) x <- x + 1
Run Code Online (Sandbox Code Playgroud)

这是传递给 的函数sapply(),它将其应用于长度为 的向量n。所以所有的赋值都在那个匿名函数的框架中进行。

当您使用 时x <<- x + 1,评估仍然发生在构造函数中,但它的环境是调用环境replicate()(因为eval.parent调用),这就是赋值发生的地方。这就是为什么您会在输出中获得不断增加的值。

所以我认为你正确理解了手册,但它没有明确说明它在谈论标准评估的情况。以下段落暗示了这里发生的事情:

可以访问用作函数内部参数的实际(非默认)表达式。该机制是通过承诺实现的。当一个函数被求值时,用作参数的实际表达式与一个指向函数被调用的环境的指针一起存储在promise中。当 (if) 参数被评估时,存储的表达式在调用函数的环境中被评估。由于仅使用指向环境的指针,因此在此评估期间对该环境所做的任何更改都将生效。然后,结果值也存储在 Promise 中的一个单独位置。后续评估会检索此存储值(不执行第二次评估)。也可以使用替换来访问未计算的表达式。

但帮助页面replicate()并没有说明这是它在做什么。

顺便说一句,您的标题询问了应用家庭功能:但除了replicate明确要求功能外,大多数功能都不会出现,因此不会出现此问题。例如,很明显这不会影响 global x

sapply(integer(10), function(i) x <- x + 1)
Run Code Online (Sandbox Code Playgroud)