访问具有原始函数名称的函数参数

Access function arguments with names of primitive functions

我正在尝试理解如下用户定义函数的行为(基于对 this 问题的第一个答案),returns 作为命名列表提供给它的参数:

function(a, b, ...) {                                                                      
    argg <- c(as.list(environment()), list(...))
    print(argg)
}

本质上,当其中一个参数名称也是原始函数的名称时,像上面这样的函数会产生意想不到的行为,该函数的唯一参数是 ...

下面是一些可重现的例子。

示例 1 - 函数按预期运行,缺少参数不会导致错误

#define function as above
fun1 <- function(a, b, ...) {                                                                      
          argg <- c(as.list(environment()), list(...))
          print(argg)
            }
        
    #run function
    fun1(a = 1)
    
    #returns the below. note that $b has the missing argument and this does not cause an error
    #$a
    #[1] 1
    
    #$b

    

示例 2 - 如果 'c' 是显式参数之一并且缺少

,则函数 returns 出错
#define function as above but with new explicit argument, called 'c'
#note that c() is a primitive function whose only parameter is ...

fun2 <- function(a, b, c, ...) {                                                                      
          argg <- c(as.list(environment()), list(...))
          print(argg)
            }
        
    #run function
    fun2(a = 1)

#returns error:
#Error in c(as.list(environment()), list(...)) :
#  argument "c" is missing, with no default

示例 3 - 将 'c' 替换为 'switch',一个参数不是 ...

的原始函数
#define function same way as fun2, but change 'c' parameter to 'switch'
#note that switch() is a primitive function that has parameters other than ...
fun3 <- function(a, b, switch, ...) {                                                                      
          argg <- c(as.list(environment()), list(...))
          print(argg)
            }

#run function
fun3(a = 1)

#returns the below. note that $b and $switch have the missing argument and this does not cause an error
#$a
#[1] 1

#$b

#$switch

我已经尝试了上面的许多变体,考虑到基本模式应该是清晰的,因此在没有特定代码段落的情况下很容易重现,但在这里打印似乎毫无意义;可以说,据我所知,函数 returns 如果其中一个参数 a.) 与原始函数同名,其唯一参数是 [=15= ,则似乎是一个错误] 和 b.) 也不见了。我没有测试其他更改(例如从用户定义函数的参数中删除 ...;更改调用函数或定义函数时指定参数的顺序;更改其他参数的名称和数量调用函数或定义函数等时指定​​的参数)对行为是否符合预期有影响。

另一点需要注意的是,如果我定义一个与 fun2 具有相同参数的函数,并且仍然缺少 c 参数,如果我不尝试访问函数的参数在里面。例如:

    #define function with same parameters but different content to fun2

    fun4 <- function(a, b, c, ...) {                                                                      
              return(a+b)
                }
            
        #run function
        fun4(a = 1, b = 2)

#returns
#[1] 3

请有人解释为什么我看到这种行为模式,以及只有 ... 作为参数的原始函数显然发挥关键作用的原因。

请不要提交建议 'workarounds' 或质疑手头问题的实际意义的答案或评论。我问我的问题并不是为了解决一个具体的实际问题,我也没有理由想到为什么我会被迫使用原始函数的名称作为参数;相反,我想了解错误发生的原因,以便更清楚地了解一般情况下的功能,以及用于访问其参数的过程在 R 中的工作方式。

不是 ... 引起的问题。当您调用 c() 时,R 在环境中查找函数定义。在函数之外,它通常会发现它是 base::c。但是在您的函数中,它首先在函数调用的参数 c 中查找定义,然后找不到。这种调用方式表明它可以通过告诉 R 具体在哪里找到 c:

的定义来工作
fun4 <- function(a, b, c, ...) {                                                                      
  argg <- base::c(as.list(environment()), list(...))
  print(argg)
}

#run function
fun4(a = 1)
#> $a
#> [1] 1
#> 
#> $b
#> 
#> 
#> $c

环境 - 来自 Advanced R

要演示调用对象的位置,您可以使用 Advanced R by Hadley Wickham 中的技巧来查看 R 在哪里找到每个对象。在 c 不是参数的函数中,它在 base 中找到它,否则它在函数环境中“找到”它(其中 ab 也是定义):

library(rlang)

where <- function(name, env = caller_env()) {
  if (identical(env, empty_env())) {
    stop("Can't find ", name, call. = FALSE)
  } else if (env_has(env, name)) {
    env
  } else {
    where(name, env_parent(env))
  }
}


fun5 <- function(a, b, ...) {   
  print(where("a"))
  print(where("b"))
  print(where("c"))
}

#run function
fun5(a = 1)
#> <environment: 0x000000001de35890>
#> <environment: 0x000000001de35890>
#> <environment: base>

fun6 <- function(a, b, c, ...) {   
  print(where("a"))
  print(where("b"))
  print(where("c"))
}

#run function
fun6(a = 1)
#> <environment: 0x000000001e1381f0>
#> <environment: 0x000000001e1381f0>
#> <environment: 0x000000001e1381f0>

reprex package (v2.0.1)

于 2021-12-15 创建