R:使省略号中的命名项在(也许是嵌套的)执行环境中可用

时间:2018-10-05 22:31:52

标签: r function nested parameter-passing ellipsis

我希望能够在已与省略号(...,AKA点)匹配的函数参数中传递命名对象,以使其在该函数或所执行函数的执行环境中普遍可用在该环境中定义的任何位置,就像在其中键入参数一样。

我尝试使用list2env(),对于一个函数,在该函数外部定义一个嵌套函数,并在该函数内部定义一个嵌套函数,该函数应将其参数列表的元素返回到parent.frame()环境,据我所知是调用环境。因此:

# Ellipsis in nested functions
inner_f1<- function(x){list2env(list(...)[-1L]); x + b}

outer_f <- function(x, ...){
  list2env(list(...)[-1L])
  in01 <- x + a
  inner_f2 <- function(x){list2env(list(...)[-1L]); print(ls()); x + c}
  in02 <- inner_f2(x)  
  in03 <- inner_f1(x)
  out <- list(in01, in02, in03)
}

outer_f(x=0, a=1, b=2, c=3)

我在嵌套函数的定义中尝试了带或不带...的情况,但是都没有用。所需的输出将是:

$ in01
[1] 1
$ in02
[1] 2
$ in03
[1] 3

“帮助”下的R帮助文件不提供有关将...值传递给内部函数的信息,并且它提及从...中获取信息的唯一方法是通过..(n)方法。它指的是“ R的简介”,但是par的例子似乎错误地暗示,内部函数拥有自己的...就足够了,尽管par代码(此处未引用)通过以下方式获取内容:对args = list(...)做复杂的事情,R语言定义也描述了list(...)方法。我还没有找到在R基本软件包中经常使用的成语替换(list(...))[-1],在任何地方都正式记录过,但是无论如何都没有这个或eval(substitute(alist(...) ))来自“高级R” ::非标准评估似乎可以满足我的要求。

关于stackoverflow上关于... s和嵌套函数的问题,有很多答案,但是我读的15篇文章似乎比我寻求的通用方法更加专业。

2 个答案:

答案 0 :(得分:1)

请注意,可用变量与ls()列出的变量不同。特别是,ls()不会列出父环境中的变量,但父环境中的变量仍可用作输入(如果使用<<-,也可用作输出)。我们假设您只是希望变量可用,而不关心ls()。 (如果您确实想将外部函数的执行环境中的变量实际注入内部函数,则将...传递给内部函数,并使用与此处所示的外部函数相同的方法。)以下示例显示了而b是可访问的,它不会显示在ls()的输出中。

f1 <- function() { 
  b <- 1
  f2 <- function() { 
    print(b)  # will print the value of b showing b is accessible
    print(ls()) # no variables will be shown
  }
  f2() 
}
f1()

给予:

[1] 1
character(0)

现在回到这个问题,这里是一些替代方法:

1)和一起尝试with

inner_fun0 <- function() in1

outer_fun <- function(...) with(list(...), {
  inner_fun <- function() in1
  environment(inner_fun0) <- environment()
  list(in1, inner_fun(), inner_fun0())
})
outer_fun(in1 = 7)

给予:

[[1]]
[1] 7

[[2]]
[1] 7

[[3]]
[1] 7

2)list2env 的替代方法是像这样使用list2env

outer_fun2 <- function(...) {
  list2env(list(...), environment())
  inner_fun <- function() in1
  environment(inner_fun0) <- environment()
  list(in1, inner_fun(), inner_fun0())
}
outer_fun2(in1 = 7)

给予:

[[1]]
[1] 7

[[2]]
[1] 7

[[3]]
[1] 7

您可以使用overwrite variable in parent function from inner function without making variable outside parent function

中的想法来构造其他变体

proto包也可以用于将所有这些包重铸到面向对象的框架中。

答案 1 :(得分:1)

替代方法:

# note how I add an argument to specify the exact environment:
inner_f1<- function(x, env, ...){
  with(env, {list2env(list(...)); x + b})
 }

outer_f <- function(x, ...){

  # get the "address", i.e. the environment:
  here <- environment()

  # specify the environment in list2env:
  list2env(list(...), envir = here)
  in01 <- x + a

  inner_f2 <- function(x){list2env(list(...), envir = here); print(ls()); x + c}
  # alternatively, use: list2env(list(...), envir = parent.frame(n=2))

  in02 <- inner_f2(x)  

  in03 <- inner_f1(x, here)

  out <- list(in01, in02, in03)
  return(out)
}

outer_f(x=0, a=1, b=2, c=3)

[1] "x"
[[1]]
[1] 1

[[2]]
[1] 3

[[3]]
[1] 2

本质上,您需要确保所有功能都可以使用正确的“地址”。