16

I have a question about function environments in the R language. I know that everytime a function is called in R, a new environment E is created in which the function body is executed. The parent link of E points to the environment in which the function was created.

My question: Is it possible to specify the environment E somehow, i.e., can one provide a certain environment in which function execution should happen?

Bijoy Thangaraj
  • 5,434
  • 4
  • 43
  • 70
Sven Hager
  • 3,144
  • 4
  • 24
  • 32
  • 2
    Anything wrong with `environment(fun) <- value` as described in `?environment`? – Joshua Ulrich Sep 05 '12 at 10:15
  • This just changes the parent link, I suppose. I am looking for a way to change the environment in which execution happens. – Sven Hager Sep 05 '12 at 10:19
  • 1
    You can evaluate a function call in an environment other than the global environment, but that will still generate a new environment *within* the function but now the parent of that environment will be the environment you evaluated it in not the global environment. Would that do? If so see `?with` and `?eval`, the latter a lower level function used by `with()`. – Gavin Simpson Sep 05 '12 at 10:25
  • No, this is not what I am looking for. I really want to change the newly created environment in which function execution happens. – Sven Hager Sep 05 '12 at 10:31
  • 3
    So could you alter the function so that sets up the call you want and evaluates that inside the specified environment. Then you would have GlobalEnv > fun execution env > eval call in specified env. I don't think you can stop R creating a new environment when the function is called, but you could modify the function body to do its work in the specified environment not the one R created (which will still exist and be created of course, you are just changing environments after that.) – Gavin Simpson Sep 05 '12 at 10:37
  • 3
    You need to be more specific as to what you want to change about the environment in which you execute the function. Add a certain object? Change environment variables? – Paul Hiemstra Sep 05 '12 at 10:39
  • 1
    @amonk (sponsor of the bounty): Please also describe the restrictions you are expecting, e. g.: Is it allowed the change the function bodies of the affected functions, is it allowed to wrap the functions, is it allowed to modify each code point the executes the function, do you also want to modify functions coming from packages... – R Yoda Apr 01 '18 at 21:27
  • @RYoda sure! Since the OP did not specify an example you're free to be creative – amonk Apr 01 '18 at 21:37

3 Answers3

19

A function has an environment that can be changed from outside the function, but not inside the function itself. The environment is a property of the function and can be retrieved/set with environment(). A function has at most one environment, but you can make copies of that function with different environments.

Let's set up some environments with values for x.

x <- 0
a <- new.env(); a$x <- 5
b <- new.env(); b$x <- 10

and a function foo that uses x from the environment

foo <- function(a) {
    a + x
}
foo(1)
# [1] 1

Now we can write a helper function that we can use to call a function with any environment.

with_env <- function(f, e=parent.frame()) {
    stopifnot(is.function(f))
    environment(f) <- e
    f
}

This actually returns a new function with a different environment assigned (or it uses the calling environment if unspecified) and we can call that function by just passing parameters. Observe

with_env(foo, a)(1)
# [1] 6
with_env(foo, b)(1)
# [1] 11
foo(1)
# [1] 1
MrFlick
  • 195,160
  • 17
  • 277
  • 295
5

Here's another approach to the problem, taken directly from http://adv-r.had.co.nz/Functional-programming.html

Consider the code

new_counter <- function() {
  i <- 0
  function() {
    i <<- i + 1
    i
  }
}

(Updated to improve accuracy) The outer function creates an environment, which is saved as a variable. Calling this variable (a function) effectively calls the inner function, which updates the environment associated with the outer function. (I don't want to directly copy Wickham's entire section on this, but I strongly recommend that anyone interested read the section entitled "Mutable state". I suspect you could get fancier than this. For example, here's a modification with a reset option:

new_counter <- function() {
  i <- 0
  function(reset = FALSE) {
    if(reset) i <<- 0
    i <<- i + 1
    i
  }
}

counter_one <- new_counter()
counter_one()
counter_one()
counter_two <- new_counter()
counter_two()
counter_two()
counter_one(reset = TRUE)
Melissa Key
  • 4,476
  • 12
  • 21
2

I am not sure I completely track the goal of the question. But one can set the environment that a function executes in, modify the objects in that environment and then reference them from the global environment. Here is an illustrative example, but again I do not know if this answers the questioners question:

e <- new.env()
e$a <- TRUE
testFun <- function(){
  print(a)
}
testFun()

Results in: Error in print(a) : object 'a' not found

testFun2 <- function(){
  e$a <- !(a) 
  print(a)
}
environment(testFun2) <- e
testFun2()

Returns: FALSE

e$a 

Returns: FALSE

Ian Wesley
  • 3,565
  • 15
  • 34