Parent.env(x) путаница

Я прочитал документацию для parent.env(), и она кажется довольно простой - она ​​возвращает окружение. Однако, если я использую parent.env(), чтобы ходить по цепочке окружающих сред, я вижу то, что я не могу объяснить. Во-первых, код (взятый из "R в двух словах" )

library( PerformanceAnalytics )
x = environment(chart.RelativePerformance)
while (environmentName(x) != environmentName(emptyenv())) 
{ 
    print(environmentName(parent.env(x)))
    x <- parent.env(x)
}

И результаты:

[1] "imports:PerformanceAnalytics"
[1] "base"
[1] "R_GlobalEnv"
[1] "package:PerformanceAnalytics"
[1] "package:xts"
[1] "package:zoo"
[1] "tools:rstudio"
[1] "package:stats"
[1] "package:graphics"
[1] "package:utils"
[1] "package:datasets"
[1] "package:grDevices"
[1] "package:roxygen2"
[1] "package:digest"
[1] "package:methods"
[1] "Autoloads"
[1] "base"
[1] "R_EmptyEnv"

Как мы можем объяснить "базу" наверху и "базу" внизу? Кроме того, как мы можем объяснить "пакет: PerformanceAnalytics" и "import: PerformanceAnalytics"? Все казалось бы последовательным без первых двух строк. То есть, функция chart.RelativePerformance находится в пакете: среда PerformanceAnalytics, созданная xts, которая создается зоопарком,... полностью вверх (или вниз) на базовую и пустую среду.

Кроме того, документация не очень понятна для этого - это "окружающая среда" - среда, в которой создается другая среда, и, таким образом, ходьба parent.env() показывает цепочку создания?

Edit

Бесстыдный плагин: я написал сообщение в блоге, в котором объясняются среды, parent.env(), оболочки, пространство имен/пакет и т.д. с интуитивным диаграммы.

Ответ 1

Первые несколько элементов в ваших результатах свидетельствуют о том, что правила R используются для поиска переменных, используемых в функциях в пакетах с пространствами имен. Из руководства R-ext:

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

Разработав немного, взгляните на первые несколько строк chart.RelativePerformance:

head(body(chart.RelativePerformance), 5)
# {
#     Ra = checkData(Ra)
#     Rb = checkData(Rb)
#     columns.a = ncol(Ra)
#     columns.b = ncol(Rb)
# }

Когда вычисляется вызов chart.RelativePerformance, каждый из этих символов --- будь то checkData в строке 1 или ncol в строке 3 --- должен быть найден где-то на пути поиска, Ниже перечислены первые окружные среды:

  • Прежде всего, это namespace:PerformanceAnalytics. checkData находится там, но ncol - нет.

  • Следующая остановка (и первое место, указанное в ваших результатах) imports:PerformanceAnalytics. Это список функций, указанных как импорт в пакете NAMESPACE. ncol также не найден.

  • Пространство имен base (где ncol будет найдено) является последней остановкой, прежде чем перейти к обычным траекториям поиска. Почти любая функция R будет использовать некоторые функции base, поэтому эта остановка гарантирует, что ни одна из этих функций не может быть разбита объектами в глобальной среде или в других пакетах. (Дизайнеры R могли оставить это, чтобы авторы пакетов явно импортировали среду base в свои файлы NAMESPACE, но добавление этого пропуска по умолчанию через base кажется лучшим решением дизайна.)

Ответ 2

1) Относительно того, как base может быть там дважды (учитывая, что среда формирует дерево), его ошибка в функции environmentName. На самом деле первое вхождение .BaseNamespaceEnv, а последнее вхождение - baseenv().

> identical(baseenv(), .BaseNamespaceEnv)
[1] FALSE

2) Что касается imports:PerformanceAnalytics, который является специальной средой, которую R устанавливает для хранения импортируемых в пакете файлов NAMESPACE или DESCRIPTION, чтобы объекты в ней встречались раньше всего.

Попробуйте выполнить это для некоторой ясности. Операторы str(p) и следующих if будут лучше понимать, что p:

library( PerformanceAnalytics )
x <- environment(chart.RelativePerformance)
str(x)
while (environmentName(x) != environmentName(emptyenv())) { 
    p <- parent.env(x)
    cat("------------------------------\n")
    str(p)
    if (identical(p, .BaseNamespaceEnv)) cat("Same as .BaseNamespaceEnv\n")
    if (identical(p, baseenv())) cat("Same as baseenv()\n")
    x <- p
}

Ответ 3

Второй base - .BaseNamespaceEnv, а второй - base - baseenv(). Это не разные (вероятно, w.r.t. его родители). Родитель .BaseNamespaceEnv - .GlobalEnv, а baseenv() - emptyenv().

В пакете, как @Josh говорит, R ищет пространство имен пакета, затем импортирует, а затем базу (т.е. BaseNamespaceEnv).

вы можете найти это, например:

> library(zoo)

> packageDescription("zoo")
Package: zoo

# ... snip ...

Imports: stats, utils, graphics, grDevices, lattice (>= 0.18-1)

# ... snip ...

> x <- environment(zoo)

> x
<environment: namespace:zoo>

> ls(x) # objects in zoo
  [1] "-.yearmon"                "-.yearqtr"                "[.yearmon"               
  [4] "[.yearqtr"                "[.zoo"                    "[<-.zoo"                 
# ... snip ...

> y <- parent.env(x)
> y # namespace of imported packages
<environment: 0x116e37468>
attr(,"name")
[1] "imports:zoo"

> ls(y) # objects in the imported packages

   [1] "?"                                     "abline"                               
   [3] "acf"                                   "acf2AR"                               
# ... snip ...