Jos*_*ood 8 parameters r function ellipsis
我的目标是获取通过省略号传递的附加参数...(请参阅?dots参考资料 获取更多信息),并使用已设置的参数构建一个新的通用函数,并将其传递给另一个函数。
例如,给定两个函数:
foo <- function(v, FUN, ...) {
## code here to build NEWFUN
SomeFun(v, NEWFUN)
}
bar <- function(v, FUN) {
SomeFun(v, FUN)
}
Run Code Online (Sandbox Code Playgroud)
我希望能够在以下位置执行此操作foo:
bar(x, FUN = \(x) paste(x, collapse = ", "))
Run Code Online (Sandbox Code Playgroud)
通过调用foo(x, paste, collapse = ", ").
我们从一个简单的函数开始,它采用一个基R函数(此处paste)并将其应用于向量。请注意,我试图使其尽可能简单,因此我删除了健全性检查。另外,我写这个只是为了用基本R函数来演示paste。
FunAssign <- function(f, x) f(x)
Run Code Online (Sandbox Code Playgroud)
这是我天真的尝试:
foo <- function(v, FUN, ...) {
FUN <- \(x) FUN(x, ...)
FunAssign(FUN, v)
}
Run Code Online (Sandbox Code Playgroud)
调用它,我们得到错误:
foo(letters[1:5], paste, collapse = ", ")
#> Error in FUN(x, ...) : unused argument (collapse = ", ")
Run Code Online (Sandbox Code Playgroud)
如上所述,调用时所需的输出可以通过如下foo(letters[1:5], paste, collapse = ", ")调用来模拟:bar
bar <- function(v, FUN) FunAssign(FUN, v)
bar(letters[1:5], FUN = \(x) paste(x, collapse = ", "))
#> [1] "a, b, c, d, e"
Run Code Online (Sandbox Code Playgroud)
我认为我的尝试foo会起作用,因为如果我们执行如下所示的操作,那么我们似乎走在正确的轨道上:
baz <- function(FUN, ...) \(x) FUN(x, ...)
baz(paste, collapse = ", ")(letters[1:5])
#> [1] "a, b, c, d, e"
Run Code Online (Sandbox Code Playgroud)
我找到了一些几乎可以满足我的要求的资源,但没有一个完全符合我的要求。
do.call评估了表达式。我认为如果您不覆盖FUN中的变量,您的第一个想法就会起作用foo()。也就是说,这对我有用:
FunAssign <- function(f, x) f(x)
foo <- function(v, FUN, ...) {
force(FUN)
FUN2 <- \(x) FUN(x, ...)
FunAssign(FUN2, v)
}
foo(letters[1:5], paste, collapse = ", ")
Run Code Online (Sandbox Code Playgroud)
除了重命名 中的第二个FUN之外foo(),我还添加了force(FUN)命令。在本示例中这不是必需的,但一般来说,确保对创建的函数中所需的参数进行求值是一个好主意。我认为这会在这段代码中自动发生(因为FunAssign将使用它),但我对类似的事情很迷信。
编辑添加:对此的解释相当简单。
FUN函数中的变量在被调用FUN2()之前不会被求值FUN2()。FUN2被调用时FunAssign(FUN2, v),R 尝试评估FUN(x, ...)。FUN未在该函数中定义,R 会在父环境中查找,并FUN在求值框架中找到 ,foo()作为函数调用的参数。FUN,该查找发生在您用不同的变量(我调用的函数FUN2)覆盖参数之后。FUN(x, ...),在您的代码中,FUN它正在使用的是在那里定义的那个,并且 R 尝试递归调用,但会给出错误,因为该函数只有一个名为 的参数x。这里的关键是函数体只是一个未计算的表达式。在您调用该函数之前,它不会被求值,此时 R 会尝试查找它使用的所有对象,包括它调用的函数。