【问题标题】:How does R know to use a function, if that functions name has been reassigned to a value?如果函数名称已重新分配给一个值,R 怎么知道要使用该函数?
【发布时间】:2018-05-03 02:03:36
【问题描述】:

我知道在命名变量时最好不要使用全局命名空间中的名称,但是如果你不小心这样做了会发生什么?

我以为我会丢失之前的对象,但 R 似乎有些诡计:

print(sd)
#> function (x, na.rm = FALSE) 
#> sqrt(var(if (is.vector(x) || is.factor(x)) x else as.double(x), 
#>     na.rm = na.rm))
#> <bytecode: 0x0000000017e687b8>
#> <environment: namespace:stats>

sd <- 12.2

print(sd)
#> [1] 12.2

sd(1:10)
#> [1] 3.02765

所以现在 R 知道在全局命名空间中有一个长度为一的双精度向量 sd 和一个统计函数 sd()

或者当我调用sd(1:10) 时,解释器会自动将其扩展为sd.default()?但是 R 怎么知道在 sd 上寻找默认方法,因为它现在是一个向量?那么存储在内存中不同位置的函数和变量可以被同名引用吗?

obviously_a_user_defined_variable <- 257
obviously_a_user_defined_variable(1:10)
#> Error in obviously_a_user_defined_variable(1:10): could not find 
#  function "obviously_a_user_defined_variable"

【问题讨论】:

  • 简单回答:sd(1:10) 是对函数sd 的调用。因此,R 会查找一个名为 sd() 的函数,它可以在预加载的 stats 包中找到。
  • 您要使用的术语(和标记)是 'shadowing',如“同名变量正在对函数进行阴影处理”。严格来说,函数的名称没有被“重新分配”。

标签: r shadowing


【解决方案1】:

R 有separate namespaces for functions and variables。根据名称出现的上下文,R 将在一个名称空间或另一个名称空间中查找名称。

例如,表达式sd(1:10) 是一个调用,调用中的第一个元素必须是函数的名称。因此,在这种情况下,R 将查找名为 sd 的函数。

另一方面,表达式sd 不是一个调用,而是一个名称,它可以是变量的名称,也可以是函数的名称。在这种情况下,R 将首先在名为 sd 的搜索路径中查找第一个对象,无论它是函数还是其他类型的对象。

【讨论】:

  • 很好的参考,我想我更喜欢 Lisp-1 场景,其中名称指向一件事且仅指向一件事。这样可以减少歧义。但也许 R 的方法有好处
  • R 非常灵活。你绝对可以做任何事情,即使是可怕的技巧,它总是有效的。这是它的强项和弱点。作为一名开发人员,我确实同意你的观点,但要务实一点,不管你写的废话有用和方便,R 总是可以工作。
  • 这句话的最后一部分不太对;没有括号,R 会在名为 sd 的搜索路径中查找第一件事,无论它是否是对象的函数,例如mtcars &lt;- function() 'foo'; mtcars
  • 这是否意味着分配名称的命名空间取决于运行时检查,其中 a &lt;- b 分配给不同的名称取决于 b 查找找到的内容?
  • 我认为这并不完全正确,例如运行a &lt;- mean; a &lt;- 5; a(1:10) 会报错,因为函数a 已被变量覆盖。是的,当使用括号a() 时,R 会在搜索路径上查找名为a 的函数并避开其他对象,但我认为函数和变量没有单独的命名空间。
【解决方案2】:

sd 属于stats 环境而不是globalenv。调用sd() R 查找函数sd。它不在 globalenv 中,因此它会查看其他环境,直到找到函数 sd

这称为词法作用域,在 Hadley 的书籍 http://adv-r.had.co.nz/ 中有解释。可能在这一章http://adv-r.had.co.nz/Environments.html 或这一章http://adv-r.had.co.nz/Functions.html

【讨论】:

  • search() 路径解释了它在哪里找到它们(以及为什么它在sd() 之前找到sd),但没有解释为什么它一直在寻找sd(),这可能是因为括号意味着它被解释为函数调用而不是对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-30
  • 2018-12-26
  • 1970-01-01
  • 2020-09-17
  • 2021-07-24
  • 2018-02-22
相关资源
最近更新 更多