-1

In the book, the exercise is on page 10/23 of the Environments chapter, after section Iteration vs. Recursion. It is

Modify where() to find all environments that contain a binding for name.

Here, where() is from the pryr package. First of all, to be sure I understand what is asked: Say I have the name mean. This could refer to:

> mean
function (x, ...) 
UseMethod("mean")
<bytecode: 0x2234b58>
<environment: namespace:base>

But also, say I assign a value to a variable of the same name:

> mean <- 3
> mean
[1] 3

So, now (please correct me if I'm wrong), the former mean is bound by the baseenv() whereas the latter is bound by globalenv(). Correct?

> ls(as.environment(globalenv()))
[1] "mean"
> which(ls(as.environment(baseenv()))=="mean")
[1] 671

So I wrote:

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))
  }
}

inspired by the where function from the pryr package.

I was hoping I could now do (at the R prompt):

> source("./where2.r")
> mean <- 3
> k <- list()
> where2(k, "mean", parent.frame())
Error: Can't find mean

and get a list containint the base- and global environments.

What should I do differently and how?

TMOTTM
  • 3,286
  • 6
  • 32
  • 63
  • To find all environments that contain an object named "mean" you could use `find("mean")` which results in `[1] ".GlobalEnv" "package:base"` – R Yoda Nov 06 '17 at 22:09

1 Answers1

1

This function solves the problem:

    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)
  }
}