`Advanced R` book: Найти все среды, содержащие привязку для`name`
В книге упражнение находится на странице 10/23 Environments
глава, после раздела Iteration vs. Recursion
, это
изменять
where()
найти все среды, содержащие привязку дляname
,
Вот, where()
от pryr
пакет. Прежде всего, чтобы быть уверенным, что я понимаю, что спрашивают: скажем, у меня есть имя mean
, Это может относиться к:
> mean
function (x, ...)
UseMethod("mean")
<bytecode: 0x2234b58>
<environment: namespace:base>
Но также, скажем, я присваиваю значение переменной с тем же именем:
> mean <- 3
> mean
[1] 3
Итак, сейчас (пожалуйста, поправьте меня, если я ошибаюсь), бывший mean
связан baseenv()
в то время как последний связан globalenv()
, Правильный?
> ls(as.environment(globalenv()))
[1] "mean"
> which(ls(as.environment(baseenv()))=="mean")
[1] 671
Итак, я написал:
where2 <- function(k, name, env) {
stopifnot(is.character(name), length(name) == 1)
# Why does this only work when calling 'where' from
# the 'pryr' package?
# env <- to_env(env)
# Hopefully the same as 'to_env'.
# env <- as.environment(env)
# Successful case.
if(exists(name, env, inherits=FALSE)) {
k <- list(k, env)
where2(k, name, parent.env(env))
}
# Base case or search one level up.
if(identical(env, emptyenv())) {
stop("Can't find ", name, call.=FALSE)
} else {
where2(k, name, parent.env(env))
}
}
вдохновленный where
функция от pryr
пакет.
Я надеялся, что теперь смогу сделать (в приглашении R):
> source("./where2.r")
> mean <- 3
> k <- list()
> where2(k, "mean", parent.frame())
Error: Can't find mean
и получить список, содержащий в базовой и глобальной среде.
Что я должен делать по-другому и как?
1 ответ
Эта функция решает проблему:
where_2 = function (name, env = parent.frame(), env_list = list())
{
stopifnot(is.character(name), length(name) == 1)
env <- as.environment(env)
if (identical(env, emptyenv())) {
if (length(env_list) == 0) {
stop("Can't find ", name, call.=FALSE)
} else {
return(env_list)
}
} else if (exists(name, env, inherits = FALSE)) {
env_list = append(env_list, env)
where_2(name, parent.env(env), env_list = env_list)
}
else {
where_2(name, parent.env(env), env_list = env_list)
}
}