问题
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