Choosing a nested function environment

I write some functions to perform repetitive tasks, but I try to minimize the amount of data downloaded. Basically, I have one function that takes some information and makes the plot. Then I have a second function that will cycle through and output several graphs in .pdf. In both functions, I have the following line of code:

if(load.dat) load("myworkspace.RData") 

where load.dat is logical and the data I need is stored in myworkspace.RData. When I call a wrapper function that traverses and displays multiple graphs, I don’t want to reload the workspace in every call to the internal function. I thought I could just load the workspace once in a wrapper function, then the inner function could access this data, but I got an error message otherwise.

So, I realized that the function cannot find the variable in its local environment (created when the function was called), the function will look for the parent environment for the variable.

I assumed that the parent environment for calling the internal function would be an external function call. This is obviously not true:

 func1 <- function(...){ print(var1) } func2 <- function(...){ var1 <- "hello" func1(...) } > func2() Error in print(var1) : object 'var1' not found 

After reading numerous questions, a language guide, and this really useful blog post, I came up with the following:

 var1 <- "hello" save(list="var1",file="test.RData") rm(var1) func3 <- function(...){ attach("test.RData") func1(...) detach("file:test.RData") } > func3() [1] "hello" 

Is there a better way to do this? Why func1 n't func1 looking for undefined variables in the local environment created by func2 when it was func2 that called func1 ?

Note. I did not know what to call this question. If anyone has the best suggestions, I will change it and edit this line.

+6
source share
2 answers

To illustrate lexical reach, consider the following:

First create an environment for the sandbox, only to avoid the so-called R_GlobalEnv:

 sandbox <-new.env() 

Now we put two functions in it: f , which looks for a variable named x ; and g , which defines local x and calls f :

 sandbox$f <- function() { value <- if(exists("x")) x else "not found." cat("This is function f looking for symbol x:", value, "\n") } sandbox$g <- function() { x <- 123 cat("This is function g. ") f() } 

Technical information: entering functions in the console causes the environment to be set to R_GlobalEnv , so we manually force the f and g shells to correspond to the environment in which they "belong":

 environment(sandbox$f) <- sandbox environment(sandbox$g) <- sandbox 

Call g . Local variable x=123 not found f :

 > sandbox$g() This is function g. This is function f looking for symbol x: not found. 

Now we create x in the global environment and call g . The f function will look for x first in the sandbox, and then in the parent slot of the sandbox, which turns out to be R_GlobalEnv:

 > x <- 456 > sandbox$g() This is function g. This is function f looking for symbol x: 456 

To make sure that f searches for x first in its application, we can put x there and call g :

 > sandbox$x <- 789 > sandbox$g() This is function g. This is function f looking for symbol x: 789 

Conclusion: A character search in R follows an environment chain, and not with evaluation frames created during the execution of nested function calls.

EDIT: just add a link to this very interesting Martin Morgan answer on parent.frame() vs parent.env()

+7
source

You can use closure:

 f2 <- function(...){ f1 <- function(...){ print(var1) } var1 <- "hello" f1(...) } f2() 
+2
source

Source: https://habr.com/ru/post/952118/


All Articles