代码之家  ›  专栏  ›  技术社区  ›  andrewH

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

  •  3
  • andrewH  · 技术社区  · 6 年前

    我希望能够在与省略号(…,AKA dots)匹配的函数的参数中传递命名对象,使其在该函数的执行环境中或在该环境中执行的函数的执行环境(无论在何处定义)中普遍可用,就好像参数是在那里键入的一样。

    我试着这样做,对于一个函数,一个在该函数外部定义的嵌套函数,以及一个在该函数内部定义的嵌套函数,使用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
    

    “dots”下的R帮助文件不提供有关传递的信息。。。内部函数的值,以及它提到的从一个。。。是通过..(n)方法。它指的是“对R的介绍”,但是par的例子似乎错误地表明,内部函数有自己的…就足够了,尽管par代码(这里没有引用)通过做复杂的事情来获取内容 args = list(...) ,并且R语言定义还描述了list(…)方法。我还没有找到惯用语substitute(list(…)[-1),它经常被用在R基本包中,在任何地方都有正式的文档记录,但是在任何情况下,这个和来自“Advanced R”的eval(substitute(alist(…)))::非标准的评估似乎都不能满足我的要求。

    关于…s和嵌套函数的问题,这里有很多答案,但我读到的15个左右的答案似乎都比我正在寻找的广义方法更专业。

    2 回复  |  直到 6 年前
        1
  •  4
  •   G. Grothendieck    6 年前

    请注意,可用的变量与 ls() . 特别地, ls() 不会列出父环境中的变量,但父环境中的变量仍可用作输入(如果使用<<-)。我们假设您只需要可用的变量,而不关心 ls() 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
    

    另一种方法是使用 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] 7
    
    [[2]]
    [1] 7
    
    [[3]]
    [1] 7
    

    您可以使用中的思想构造其他变体 overwrite variable in parent function from inner function without making variable outside parent function

    此外,proto包还可以用来将所有这些重新构建成一个面向对象的框架。

        2
  •  2
  •   coffeinjunky    6 年前

    另一种选择:

    # 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
    

    本质上,您需要确保所有函数都有正确的“地址”。