Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

equivalent of within(), attach() etc. for working within an environment?

Tags:

closures

r

I want to add an environment to a search path and modify the values of variables within that environment, in a limited chunk of code, without having to specify the name of the environment every time I refer to a variable: for example, given the environment

ee <- list2env(list(x=1,y=2))

Now I would like to do stuff like

ee$x <- ee$x+1
ee$y <- ee$y*2
ee$z <- 6

but without appending ee$ to everything (or using assign("x", ee$x+1, ee) ... etc.): something like

in_environment(ee, {
    x <- x+1
    y <- y+2
    z <- 6
})

Most of the solutions I can think of are explicitly designed not to modify the environment, e.g.

  • ?attach: "The database is not actually attached. Rather, a new environment is created on the search path ..."
  • within(): takes lists or data frames (not environments) "... and makes the corresponding modifications to a copy of ‘data’"
  • There are two problems with <<-: (1) using it will cause NOTEs in CRAN checks (I think? can't find direct evidence of this, but e.g. see here — maybe this only happens because of the appearance of assigning to a locally undefined symbol? I guess I could put this in a package and test it with --as-cran to confirm ...); (2) it will try to assign in the parent environment, which in a package context [which this is] will be locked ...

I suppose I could use a closure as described in section 10.7 of the Introduction to R by doing

clfun <- function() {
   x <- 1
   y <- 2
   function(...) {
      x <<- x + 1   
      y <<- y * 2
   }
}
myfun <- clfun()

This seems convoluted (but I guess not too bad?) but:

  • will still incur problem #1 (CRAN check?).
  • I think (??) it won't work with variables that don't already exist in the environment (would need an explicit assign() for that ...)
  • doesn't allow a choice of which environment to operate in - it's necessarily going to work in the enclosing environment, not with arbitrary environment ee

Am I missing something obvious and idiomatic?

like image 753
Ben Bolker Avatar asked Sep 13 '25 03:09

Ben Bolker


1 Answers

Thanks to @Nuclear03020704 ! I think with() was what I wanted all along; I was incorrectly assuming that it would also create a local copy of the environment, but it only does this if the data argument is not already an environment.

ee <- list2env(list(x=1,y=2))
with(ee, {
    x <- x+1
    y <- y+2
    z <- 6
})

does exactly that I want.


Just had another idea, which also seems to have some drawbacks: using a big eval clause. Rather than make my question a long laundry list of unsatisfactory solutions, I'll add it here.

myfun <- function() {
    eval(quote( {
        x <- x+1
        y <- y*2
        z <- 3
    }), envir=ee)
}

This does seem to work, but also seems very weird/mysterious! I hate to think about explaining it to someone who's being using R for less than 10 years ... I suppose I could write an in_environment() based on this, but I'd have to be very careful to capture the expression properly without evaluating it ...

like image 165
Ben Bolker Avatar answered Sep 15 '25 18:09

Ben Bolker