Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

do.call specify environment inside function

Tags:

r

do.call

I'm using the following construct in a package,

## two functions in the global environment
funa <- function(x) x^2
funb <- function(x) x^3
## called within a function, fine
fun_wrap <- function(){
  lapply(c('funa', 'funb'), do.call, list(x=3))
}

fun_wrap()
[[1]]
[1] 9

[[2]]
[1] 27

but I've just been bitten by the fact that it won't work if the functions are in a different (local) frame,

## same construct, but the functions are local
fun_wrap1 <- function(){
  funa1 <- function(x) x^2
  funb1 <- function(x) x^3
  lapply(c('funa1', 'funb1'), do.call, list(x=3))
}
## now it fails
fun_wrap1()
##Error in FUN(c("funa1", "funb1")[[1L]], ...) : 
##  could not find function "funa1"

I've tried passing envir=parent.frame(2) to do.call() (doesn't work); frankly the help page of ?parent.frame goes way over my head. Any hint for a more robust use of do.call?

Note that the list of functions comes as a character vector, passed from another piece of code; I prefer not to pass the functions directly.

Edit: one more twist... I thought I'd illustrated the right problem with my toy example, but the actual code I'm using is slightly different, in the sense that I'm calling fun_wrap1 within a separate function. The proposed solutions fail in this context.

fun_wrap1 <- function(funs){
  lapply(funs, do.call, args=list(x=3), envir=environment())
}

foo <- function(){
  funa1 <- function(x) x^2
  funb1 <- function(x) x^3
 fun_wrap1(c('funa1', 'funb1'))
}

foo()
##Error in FUN(c("funa1", "funb1")[[1L]], ...) : 
##  could not find function "funa1"

(and the same happens with the match.fun approach)

I can get it to work by passing an optional environment to fun_wrap1,

fun_wrap1 <- function(funs, e=parent.frame()){
  lapply(funs, do.call, args=list(x=3), envir=e)
}

foo <- function(){
  funa1 <- function(x) x^2
  funb1 <- function(x) x^3
  fun_wrap1(c('funa1', 'funb1'))
}

foo()

and that's hopefully it.

like image 896
baptiste Avatar asked Sep 25 '14 00:09

baptiste


People also ask

Is it good practice to call a function within a function?

You can't make a function call except from within a function, so the answer to the headline question is "yes: it is not only good practice; it is unavoidable".

What is the environment function in R?

In R, the environment() function returns the environment associated with a given function or formula. An environment is a collection of objects such as functions, variables, and so on. Whenever we hit up the R interpreter, an environment is created.

What is the parent environment of a function R?

The parent environment of a function is the environment in which the function was created. If a function was created in the execution environment (for example, in the global environment), then the environment in which the function was called will be the same as the environment in which the function was created.

Which environment will R look up first?

When a function is evaluated, R looks in a series of environments for any variables in scope. The evaluation environment is first, then the function's enclosing environment, which will be the global environment for functions defined in the workspace.


1 Answers

This seems to work, but i'm not sure if it has other implications I'm not considering:

fun_wrap1 <- function(){
  funa1 <- function(x) x^2
  funb1 <- function(x) x^3
  lapply(c('funa1', 'funb1'), do.call, args=list(x=3), envir=environment())
}

fun_wrap1()
#[[1]]
#[1] 9
#
#[[2]]
#[1] 27

So this is essentially equivalent to having the lapply statement as:

lapply(
       c('funa1', 'funb1'), 
       function(f) do.call(f, args=list(x=3), envir=environment() )
      ) 
like image 92
thelatemail Avatar answered Oct 06 '22 01:10

thelatemail