kjo kjo - 2 months ago 7
R Question

How to "instantiate" an enviroment in the current one?

Suppose that the function

foo
returns its enviroment, like this:

foo <- function () {
a <- 42
b <- "a string"
x <- FALSE
environment()
}


...and that function
bar
invokes
foo
like this:

bar <- function () {
a <- 0
z <- pi

cat("before\n")
print(ls.str())

INSTANTIATE(foo())

cat("after\n")
print(ls.str())
}


...where
INSTANTIATE
is a placeholder for an as-yet undefined function (or construct).

The hypothetical expression
INSTANTIATE(foo())
is intended as shorthand for the directive


instantiate the environment returned by
foo()
in the current enviroment.


By "instantiate" I mean that all the variables mentioned in
foo()
get created (if necessary) in the current enviroment, and assigned to values they have in
foo()
.

This means that the desired output for
bar()
is the following:

> bar()
before
a : num 0
z : num 3.14
after
a : num 42
b : chr "a string"
x : logi FALSE
z : num 3.14


My question is, what should I replace the expression
INSTANTIATE(foo())
such that the output of
bar()
looks like I've shown above?

EDIT: Please assume that
foo
should remain unchanged.

EDIT: This implementation of
INSTANTIATE(foo())
, inspired by Gregor's comment (or, rather, my interpretation thereof), does not work:

bar <- function () {
a <- 0
z <- pi
cat("before\n")
print(ls.str())

list2env(as.list(foo()))

cat("after\n")
print(ls.str())
}

> bar()
before
a : num 0
z : num 3.14
after
a : num 0
z : num 3.14

Answer

How about something like this

import_env <- function(env, to=parent.frame()) {
    vars <- ls(envir=env)
    for(v in vars) {
        assign(v, get(v, env),to)
    }
}

Tested with

foo <- function () {
  a <- 42
  b <- "a string"
  x <- FALSE
  environment()
}

bar <- function () {
  a <- 0
  z <- pi

  cat("before\n")
  print(ls.str())

  import_env(foo())

  cat("after\n")
  print(ls.str())
}

bar()
# before
# a :  num 0
# z :  num 3.14
# after
# a :  num 42
# b :  chr "a string"
# x :  logi FALSE
# z :  num 3.14

Basically we just iterate the environment and assign all the variables over. This should work for atomic types. Things get a bit trickier if you ever tried to copy over functions or formulas which hold on to the environment where they were created.