【问题标题】:R: Scoping, timing, and <<-R:范围界定、时间安排和 <<-
【发布时间】:2018-02-06 20:54:20
【问题描述】:

在下面的代码中,我希望 f 和最后的 a 都返回 3。但实际上它们都返回 2。这是为什么呢?在评估 Promise 时,不是 3 替换了封闭环境中的 2 吗?

a <- 1

f <- function(a){
  a <<- 3
  cat(a)
}

f(a <- 2)
a

请注意,如果我在对 f 的调用中使用 = 而不是

【问题讨论】:

  • 这是= 和&lt;- 之间存在差异的情况之一。如果在函数调用中使用了=,则将其视为命名参数。如果您只使用a&lt;-2,那么它是一个未命名的参数,直到您运行cat(a),它才会在调用环境中进行评估,覆盖之前的全局分配。你真的想在这里做什么?
  • 扩展@MrFlick 的评论:如果您在调试f 的每一步运行get("a",envir = .GlobalEnv),您会看到它返回值1,然后是3,此时您只是即将评估cat(a)。评估首先找到 argument,而不是全局环境中的 a,因此它在调用环境中评估 a &lt;- 2,因此再次将其覆盖为 2。
  • 谢谢,乔兰,这很有帮助。所以我缺少的是,在 a 的承诺得到履行之前,不会在命令行中分配给 a 。我认为这仅适用于 = 的作业。我的意思是
  • Flick 先生,我正在努力克服我经常无法正确预测我编写的 R 代码会做什么的问题。我目前的策略是将功能评估过程分解为尽可能好的步骤(我已经 15 岁了,我认为我还没有全部完成),然后确保我真正理解每个步骤。在此过程中,我提出了很多关于该步骤的确切机制的问题,尝试验证机制的假设,并确定我仍然不了解的领域。但我仍然偶尔会遇到我不期望或不理解的结果

标签: r scope promise arguments lazy-evaluation


【解决方案1】:

让我们看一下代码

a <- 1 

将值 1 分配给全局环境中的名称 a。

f <- function(a){...}

在全局环境中创建一个保存为名称f 的函数。

f(a <- 2)

现在我们使用表达式a&lt;-2 作为参数调用函数f。此表达式不会立即计算。它作为一个承诺传递。 a 的全局值保持为 1。

现在我们输入函数f 的主体。我们传入的表达式被分配给函数作用域中的局部变量a(仍未计算)和全局变量a 仍然为1。它们都涉及符号a 的事实无关紧要。这里的两个a 变量之间没有直接联系。

a <<- 3

这通过&lt;&lt;- 将值3 分配给父作用域中的a,而不是像&lt;- 那样的本地作用域。这意味着这里引用的a 不是现在保存传递给函数的参数的本地a。所以这会将全局范围内a 的值更改为 3。最后

cat(a)

现在我们终于使用了传递给函数的值,因为这里的a 指的是本地函数范围内的a。这会触发 Promise a &lt;- 2 在调用范围(恰好是全局范围)中运行。因此,a 的全局值设置为 2。此赋值表达式返回右侧值,因此从 cat() 开始显示“2”。

函数退出并

a

在全局环境中显示a 的值,现在是a。只是f中两个表达式之间的短暂时刻的值3。

如果你在哪里打电话

f( a=2 )

这是非常不同的。现在我们不再向函数传递表达式,而是将值 2 传递给命名函数参数a。如果您尝试f(x=2),您将收到一个错误,即该函数无法识别名为“x”的参数。在这种情况下没有花哨的惰性表达式/承诺评估,因为 2 是一个常数。这将在函数调用后将全局值设置为 3。 f(a &lt;- 2) 和 f(a = a &lt;- 2) 的行为方式相同。

【讨论】:

  • 这是一个了不起的解释。我在另一篇stackoverflow帖子中的评论中,
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-10
  • 2021-04-06
  • 2020-10-26
  • 2013-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多