do.call指定函数内的环境

时间:2014-09-25 00:12:11

标签: r do.call

我在包中使用以下构造

## 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

但是,如果这些功能位于不同的(本地)框架中,它就不会被激活,

## 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"

我尝试将envir=parent.frame(2)传递给do.call()(没有工作);坦率地说,?parent.frame的帮助页面超出了我的想象。是否有更强大的使用do.call的提示?

请注意,函数列表是从另一段代码传递的字符向量;我不想直接传递函数。

编辑:还有一个转折...我想我用我的玩具示例说明了正确的问题,但我使用的实际代码略有不同,感觉我在一个单独的函数中调用fun_wrap1。在这种情况下,提议的解决方案失败了。

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"

match.fun方法也是如此)

我可以通过将可选环境传递给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()

并且希望如此。

3 个答案:

答案 0 :(得分:5)

这似乎有效,但我不确定它是否还有其他影响,我不考虑:

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

所以这基本上等同于将lapply语句作为:

lapply(
       c('funa1', 'funb1'), 
       function(f) do.call(f, args=list(x=3), envir=environment() )
      ) 

答案 1 :(得分:2)

显然,如果我们评估fun_wrap2中的函数,它就可以工作。问题中的方法问题是字符串被转换为一个处理函数内的函数,这些函数改变了查找路径。

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

答案 2 :(得分:0)

@ g-grothendieck答案的一个稍微简单的版本。我们只是将函数本身放入送到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()