In R, how to make the variables inside a function available to the lower level function inside this function?(with, attach, environment) In R, how to make the variables inside a function available to the lower level function inside this function?(with, attach, environment) r r

In R, how to make the variables inside a function available to the lower level function inside this function?(with, attach, environment)


(1) Pass caller's environment. You can explicitly pass the parent environment and index into it. Try this:

f2a <- function(P, env = parent.frame()) {    env$calls <- env$calls + 1    print(env$calls)    return(P + env$c + env$d)}a <- 1b <- 2# same as f1 except f2 removed and call to f2 replaced with call to f2af1a <- function(){    c <- 3    d <- 4    calls <- 0    v <- vector()    for(i in 1:10){        v[i] <- f2a(P=0)        c <- c+1        d <- d+1      }     return(v)}f1a()

(2) Reset called function's environment We can reset the environment of f2b in f1b as shown here:

f2b <- function(P) {    calls <<- calls + 1    print(calls)    return(P + c + d)}a <- 1b <- 2# same as f1 except f2 removed, call to f2 replaced with call to f2b#  and line marked ## at the beginning is newf1b <- function(){    environment(f2b) <- environment() ##    c <- 3    d <- 4    calls <- 0    v <- vector()    for(i in 1:10){        v[i] <- f2b(P=0)        c <- c+1        d <- d+1      }     return(v)}f1b()

(3) Macro using eval.parent(substitute(...)) Yet another approach is to define a macro-like construct which effectively injects the body of f2c inline into f1c1. Here f2c is the same as f2b except for the calls <- calls + 1 line (no <<- needed) and the wrapping of the entire body in eval.parent(substitute({...})). f1c is the same as f1a except the call to f2a is replaced with a call to f2c .

f2c <- function(P) eval.parent(substitute({    calls <- calls + 1    print(calls)    return(P + c + d)}))a <- 1b <- 2f1c <- function(){    c <- 3    d <- 4    calls <- 0    v <- vector()    for(i in 1:10){        v[i] <- f2c(P=0)        c <- c+1        d <- d+1      }     return(v)}f1c()

(4) defmacro This is almost the same as the the last solution except it uses defmacro in the gtools package to define the macro rather than doing it ourself. (Also see the Rcmdr package for another defmacro version.) Because of the way defmacro works we must also pass calls but since it's a macro and not a function this just tells it to substitute calls in and is not the same as passing calls to a function.

library(gtools)f2d <- defmacro(P, calls, expr = {    calls <- calls + 1    print(calls)    return(P + c + d)})a <- 1b <- 2f1d <- function(){    c <- 3    d <- 4    calls <- 0    v <- vector()    for(i in 1:10){        v[i] <- f2d(P=0, calls)        c <- c+1        d <- d+1      }     return(v)}f1d()


In general, I would say that any variable that is needed inside a function should be passed on through its arguments. In addition, if its value is needed later you pass it back from the function. Not doing this can quite quickly lead to strange results, e.g. what if there are multiple functions defining a variable x, which one should be used. If the amount of variables is larger, you create a custom data structure for it, e.g. putting them into a named list.


One could also use a function that redefines other functions in the specified environment.

test_var <- "global"get_test_var <- function(){  return(test_var)}some_function <- function(){  test_var <- "local"  return(get_test_var()) }some_function() # Returns "global". Not what we want here...# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~some_function2 <- function(){  test_var <- "local"  # define function locally  get_test_var2 <- function(){    return(test_var)  }  return(get_test_var2()) }some_function2() # Returns "local", but 'get_test_var2' can't be used in other places.# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~add_function_to_envir <- function(my_function_name, to_envir) {  script_text <- capture.output(eval(parse(text = my_function_name)))  script_text[1] <- paste0(my_function_name, " <- ", script_text[1])  eval(parse(text = script_text), envir = to_envir)}some_function3 <- function(){  test_var <- "local"  add_function_to_envir("get_test_var", environment())   return(get_test_var()) }some_function3() # Returns "local" and we can use 'get_test_var' from anywhere.

Here add_function_to_envir(my_function_name, to_envir) captures the script of the function, parses and reevaluates it in the new environment.

Note: the name of the function for my_function_name needs to be in quotes.