Как R узнает, что нужно использовать функцию, если имя этой функции было переназначено значению?

Я знаю, что рекомендуется не использовать имена из глобального пространства имен при именовании переменных, но что произойдет, если вы сделаете это случайно?

Я думал, что потеряю предыдущий объект, но 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"

person rdh    schedule 19.11.2017    source источник
comment
Простой ответ: sd(1:10) — это вызов функции sd. Итак, R ищет функцию под названием sd(), которую он находит в предварительно загруженном пакете статистики.   -  person Rich Scriven    schedule 20.11.2017
comment
Термин (и тег), который вы хотите использовать, это "затенение", например, "переменная с тем же именем затеняет функцию". Строго говоря, имя функции не было «переназначено».   -  person smci    schedule 20.11.2017


Ответы (2)


R имеет отдельные пространства имен для функций и переменных . В зависимости от контекста, в котором встречается имя, R будет искать имя в одном пространстве имен или в другом.

Например, выражение sd(1:10) — это вызов, и первым элементом вызова должно быть имя функции. Следовательно, в этом случае R будет искать функцию с именем sd.

С другой стороны, выражение sd — это не вызов, а имя, которое может быть либо именем переменной, либо именем функции. В этом случае R сначала будет искать первый объект в пути поиска с именем sd независимо от того, является ли это функцией или другим типом объекта.

person Ernest A    schedule 19.11.2017
comment
Хорошая ссылка, я думаю, что предпочитаю сценарий Lisp-1, где имя указывает на одну вещь и только на одну вещь. Так меньше двусмысленности. Но, возможно, в подходе R есть преимущества - person rdh; 20.11.2017
comment
R очень гибкий. Вы можете делать абсолютно все, даже ужасные трюки, это всегда работает. В этом его сила и его слабость. Я согласен с вами как с разработчиком, но если быть прагматичным, то R всегда работает, какую бы ерунду вы ни написали, она полезна и удобна. - person JRR; 20.11.2017
comment
Последняя часть этого не совсем верна; без круглых скобок R ищет первую вещь в пути поиска с именем sd, независимо от того, является ли это функцией объекта, например. mtcars <- function() 'foo'; mtcars - person alistaire; 20.11.2017
comment
Означает ли это, что пространство имен, в котором назначается имя, зависит от проверки во время выполнения, где a <- b присваивается чему-то другому в зависимости от того, что находит поиск b? - person user2357112 supports Monica; 20.11.2017
comment
Это не совсем правильно, я думаю, например. запуск a <- mean; a <- 5; a(1:10) выдаст ошибку, потому что функция a была перезаписана переменной. Да, при использовании скобок a() R будет искать функцию с именем a в пути поиска и избегать других объектов, но я не думаю, что существуют отдельные пространства имен для функций и переменных. - person Axeman; 20.11.2017

sd принадлежит среде stats, а не globalenv. Вызов sd() R ищет функцию sd. Его нет в globalenv, поэтому он просматривает другие среды, пока не найдет функцию sd

Это называется лексическим охватом и объясняется в книгах Хэдли http://adv-r.had.co.nz/. Вероятно, в этой главе http://adv-r.had.co.nz/Environments.html или этот http://adv-r.had.co.nz/Functions.html

person JRR    schedule 19.11.2017
comment
Путь search() объясняет, где он их находит (и почему он находит sd раньше sd()), но не объясняет, почему он продолжает искать sd(), что, предположительно, связано с тем, что круглые скобки означают, что он интерпретируется как вызов функции, а не как объект. - person alistaire; 20.11.2017