do.call specify environment inside function

萝らか妹 提交于 2020-01-22 12:34:07

问题


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.


回答1:


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() )
      ) 



回答2:


Evidently if we evaluate the functions in fun_wrap2 it works. The problem with the approach in the question is that the character strings get converted to functions inside one of the processing functions which changes the lookup path.

fun_wrap2 <- function(){

  funa1 <- function(x) x^2
  funb1 <- function(x) x^3

  nms <- c("funa1", "funb1")
  funs <- lapply(nms, match.fun)
  lapply(funs, do.call, list(x=3))

}

fun_wrap2()



回答3:


A slightly simpler version of @g-grothendieck's answer. Rather than using the function names, we just put the functions themselves into the list that is fed to lapply.

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

fun_wrap1()


来源:https://stackoverflow.com/questions/26028488/do-call-specify-environment-inside-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!